用于按频率排序的比较器,无需创建比较器实现类

vsr*_*m92 1 java sorting comparator java-8

只是想知道我们是否可以在不编写自定义比较器类的情况下使用 Java 8 根据重复数字的频率对列表进行排序。

我需要根据给定的整数的频率,然后按自然数字顺序对给定的整数进行排序。

我在Comparator.naturalOrder()处遇到错误

这是我尝试过的代码:

Integer[] given = new Integer[]{0,0,1,22,11,22,22,11,44,555,55,66,77,88,99};
List<Integer> intList = Arrays.asList(given);


Map<Integer, Long> frequencyMap = intList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
List<Integer> newList = intList.stream().sorted(Comparator.comparing(frequencyMap::get).thenComparing(Comparator.naturalOrder())).collect(Collectors.toList());
System.out.println(newList.toString());
Run Code Online (Sandbox Code Playgroud)

预期的输出是

[1, 44, 55, 66, 77, 88, 99, 555, 0, 0, 11, 11, 22, 22, 22]
Run Code Online (Sandbox Code Playgroud)

PS:在第一行使用数组以避免在多行中使用 list.add() 并清楚理解。

Hol*_*ger 5

不幸的是,Java 的类型推断在Comparator.comparing(frequencyMap::get)thenComparing(Comparator.naturalOrder()). 由于 的方法签名Map.getget(Object),编译器推断Comparator<Object>为 的结果类型Comparator.comparing(frequencyMap::get)

您可以通过插入显式类型来解决此问题。但请注意,您没有使用 的结果,collect(Collectors.toList())而只是打印原始的、未受影响的List. 另一方面,List当给出数组时,您不需要:

Integer[] given = {0,0,1,22,11,22,22,11,44,555,55,66,77,88,99};

Map<Integer, Long> frequencyMap = Arrays.stream(given)
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Arrays.sort(given,
    Comparator.<Integer>comparingLong(frequencyMap::get)
       .thenComparing(Comparator.naturalOrder()));

System.out.println(Arrays.toString(given));
Run Code Online (Sandbox Code Playgroud)

对于不更改数组的打印,您还可以使用以下替代方法

Arrays.stream(given)
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet().stream()
    .sorted(Map.Entry.<Integer, Long>comparingByValue()
        .thenComparing(Map.Entry.comparingByKey()))
    .flatMap(e -> LongStream.range(0, e.getValue()).mapToObj(l -> e.getKey()))
    .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

这对组而不是单个值进行排序,并在计算它们时打印相同的值。