如果总和为奇数,则使用一个流从列表中删除奇数整数,如果总和为偶数,则删除偶数整数

Using one stream delete from a list odd integers if their sum is odd, delete even integers if the sum is even

我需要实现一个方法oddOrEven(List<Integer> integers):如果整数值之和为奇数,该方法应删除所有奇数元素,如果总和为偶数,该方法应删除所有偶数。

任务是实现一个时间复杂度为O(N)的方法。我可以使用局部变量,但我应该只写一个流。

这是我的两个流的解决方案。

private static List<Integer> oddOrEven(List<Integer> integers) {
    Integer sum = integers.stream().reduce(0, Integer::sum);

    return integers.stream().filter((a) -> sum % 2 == 0 && a % 2 != 0 ||
        sum % 2 != 0 && a % 2 == 0)
        .collect(toList());
}

我还尝试计算流内的总和,但这不起作用,因为 sum.value 在 List<Integer> 整数值的迭代过程中发生变化。

    private static List<Integer> oddOrEven3(List<Integer> integers) {
        class IntegerWrapper {
            private int value = 0;
        }

        final IntegerWrapper sum = new IntegerWrapper();

        return integers.stream()
                .peek((a) -> sum.value += a)
                .filter((a) -> {
                    return sum.value % 2 == 0 && a % 2 != 0 ||
                            sum.value % 2 != 0 && a % 2 == 0;
                })
                .collect(toList());
    }

请帮我弄清楚如何只用一个流来解决任务?有没有办法在流中存储在迭代期间不改变的总和?

这是一个解决方案

private static List<Integer> oddOrEven(List<Integer> integers) {
    final Map<Boolean, List<Integer>> oddsAndEvens = integers.stream()
                .collect(Collectors.partitioningBy(i -> i % 2 == 0));
    return oddsAndEvens.get(oddsAndEvens.get(false).size() % 2 != 0);
}

它的工作原理是将列表分成 2 个列表,奇数和偶数。然后它通过查看赔率列表的大小来选择要 return 的列表。

这是一种可能。

  • 使用发球收集器创建两个列表,一个是奇数,一个是偶数
  • 然后 return 根据奇数的计数得出适当的列表。这是有效的,因为偶数的赔率总和为偶数,而奇数的总和为奇数。偶数总归偶数。

public List<Integer> oddOrEven(List<Integer> values) {      
   return values.stream().collect(Collectors.teeing(
        Collectors.filtering(i -> i % 2 == 0,
                Collectors.toList()),
        Collectors.filtering(i -> i % 2 == 1,
                Collectors.toList()),
        (even, odd) -> odd.size() % 2 == 1 ? even : odd));
}

这是 @hulk 在评论中建议的另一种解决方案。我选择不使用 partitioningBy 而是 groupingBy.

public List<Integer> oddOrEven(List<Integer> values) {  
   return values.stream()
        .collect(collectingAndThen(
                Collectors.groupingBy(i -> i % 2),
                map -> map.getOrDefault(
                        (map.getOrDefault(1, List.of()).size() + 1)
                                % 2,
                        List.of())));
}

finisher和以前一样,检查奇数列表(map.get(1))的大小。 return other list 基于赔率的大小,将 1 添加到该大小,然后得到除以 2.

的余数

感谢 @Holger 建议使用 map.getOrDefault() 来处理最终映射中缺少的键。