Java 收藏家分组方式

Java Collectors Grouping By

我有一个整数输入,我想在所有奇数之前按升序对所有偶数进行排序,并保留赔率顺序。我很确定我可以通过收集器 and/or 下游收集器来实现这一点,但我不确定该怎么做。我想知道如何对错误列表进行排序,以便尽可能在一行中实现它。因此,在分组之后,我希望将错误列表按升序排序,而另一个(真实赔率列表)保持不变,并且在此转换之后能够将它们平面映射到一个列表中。

示例:

输入为:

1 6 2 3 4 5
Map<Boolean, List<Integer>> collect = Arrays
        .stream(bf.readLine().split("\s+"))
        .map(Integer::parseInt)
        .collect(Collectors.groupingBy(integer -> integer % 2 != 0));

System.out.println(collect);

上面代码的输出是:

{false=[6, 2, 4], true=[1, 3, 5]}

这行条目应该变成:

{false=[2, 4, 6], true=[1, 3, 5]}

转换后。

输出应该是偶数以排在赔率之前并按升序排序并同时保留赔率的顺序,如下所示:

2 4 6 1 3 5

使用 groupingBy 的重载,其中 takes a downstream collector

例如:

groupingBy(
    integer -> integer % 2 != 0,
    collectingAndThen(
        toList(),
        list -> list.stream().sorted().collect(toList()))

您实际上不需要分组依据。如果流是有序的,Stream.sorted 方法是一种稳定排序。

您只需要一个比较器,例如:

Comparator.comparingInt(x -> x % 2)
    // if it is even, order by natural order, otherwise they are "equal", so we map to a constant
    .thenComparingInt(x -> x % 2 == 0 ? x : 0)

示例:

Stream.of(3, 6, 2, 1, 4, 5).sorted(
    Comparator.<Integer>comparingInt(x -> x % 2)
        .thenComparingInt(x -> x % 2 == 0 ? x : 0))
    .forEachOrdered(System.out::println);

打印:

2
4
6
3
1
5

如果你想要一个 Map<Boolean, List<Integer>> 代替,你可以按奇偶校验分区(这将保证 false 键始终存在于映射中),然后对与 [= 关联的列表进行排序16=]:

Map<Boolean, List<Integer>> partitions = Stream.of(3, 6, 2, 1, 4, 5).collect(
    // collects to ArrayList to guarantee that it is mutable
    Collectors.partitioningBy(x -> x % 2 != 0, Collectors.toCollection(ArrayList::new))
);
partitions.get(false).sort(Comparator.naturalOrder());

使用 Java 12 及更高版本中可用的 Collectors.teeing 以复杂的方式解决简单问题的唯一乐趣:

List<Integer> list = List.of(3, 6, 2, 1, 4, 5);

List<Integer> result = 
    list.stream()
        .collect(Collectors.teeing(
                    Collectors.filtering(i -> i % 2 == 0, Collectors.toList()), 
                    Collectors.filtering(i -> i % 2 != 0, Collectors.toList()), 
                    (List<Integer> evens, List<Integer> odds) -> {
                        List<Integer> merged = new ArrayList<>();
                        evens.sort(Comparator.naturalOrder());
                        merged.addAll(evens);
                        merged.addAll(odds);
                        return merged;
                    }
        ));

System.out.println(result);