无需创建比较器实现即可按频率排序的比较器 class
Comparator for sorting by frequency without Creating a Comparator implementation class
只是想知道我们是否可以在不编写自定义比较器的情况下使用 Java 8 根据重复数字的频率对列表进行排序 class。
我需要根据给定的频率对给定的整数进行排序,然后再按自然数字顺序进行排序。
我在 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());
预期输出是
[1, 44, 55, 66, 77, 88, 99, 555, 0, 0, 11, 11, 22, 22, 22]
PS:在第一行使用数组以避免在多行中使用 list.add() 并便于理解。
您需要添加类型见证,编译器的小弱点:
intList.stream()
.sorted(Comparator.comparing((Integer x) -> frequencyMap.get(x))
.thenComparing(Comparator.naturalOrder()))
.forEachOrdered(System.out::println);
不幸的是,Java 的类型推断在链接 Comparator.comparing(frequencyMap::get)
和 thenComparing(Comparator.naturalOrder())
时无法识别比较对象的类型。由于 Map.get
的方法签名是 get(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));
要在不更改数组的情况下进行打印,您还可以使用以下替代方法
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);
这对组而不是单个值进行排序,并在计算相同值时打印相同的值。
只是想知道我们是否可以在不编写自定义比较器的情况下使用 Java 8 根据重复数字的频率对列表进行排序 class。
我需要根据给定的频率对给定的整数进行排序,然后再按自然数字顺序进行排序。
我在 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());
预期输出是
[1, 44, 55, 66, 77, 88, 99, 555, 0, 0, 11, 11, 22, 22, 22]
PS:在第一行使用数组以避免在多行中使用 list.add() 并便于理解。
您需要添加类型见证,编译器的小弱点:
intList.stream()
.sorted(Comparator.comparing((Integer x) -> frequencyMap.get(x))
.thenComparing(Comparator.naturalOrder()))
.forEachOrdered(System.out::println);
不幸的是,Java 的类型推断在链接 Comparator.comparing(frequencyMap::get)
和 thenComparing(Comparator.naturalOrder())
时无法识别比较对象的类型。由于 Map.get
的方法签名是 get(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));
要在不更改数组的情况下进行打印,您还可以使用以下替代方法
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);
这对组而不是单个值进行排序,并在计算相同值时打印相同的值。