简体   繁体   English

比较器,用于按频率排序,而不创建比较器实现类

[英]Comparator for sorting by frequency without Creating a Comparator implementation class

Just curious to know on whether we can sort a List according to the frequency of repeated numbers using Java 8 without writing a Custom Comparator class. 只是想知道我们是否可以在不编写Custom Comparator类的情况下使用Java 8根据重复数字的频率对List进行排序。

I need to sort the given integers based on its frequency and then by the natural numerical order. 我需要根据给定的整数频率和自然数值顺序对其进行排序。

I'm getting error at Comparator.naturalOrder(); 我在Comparator.naturalOrder()时出错

Here is the code which I tried: 这是我尝试的代码:

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());

The expected output is 预期的输出是

[1, 44, 55, 66, 77, 88, 99, 555, 0, 0, 11, 11, 22, 22, 22]

PS: Used arrays in first line in order to avoid list.add() in multiple lines and for clear understanding. PS:在第一行中使用数组,以避免在多行中使用list.add()并获得清晰的理解。

Unfortunately, Java's type inference can't recognize the type of the compared object when chaining Comparator.comparing(frequencyMap::get) with thenComparing(Comparator.naturalOrder()) . 不幸的是,当用thenComparing(Comparator.naturalOrder())链接Comparator.comparing(frequencyMap::get)时,Java的类型推断无法识别比较对象的类型。 Since the method signature of Map.get is get(Object) , the compiler infers Comparator<Object> as result type of Comparator.comparing(frequencyMap::get) . 由于Map.get的方法签名为get(Object) ,因此编译器将Comparator<Object>推断为Comparator.comparing(frequencyMap::get)结果类型。

You can fix this by inserting an explicit type. 您可以通过插入显式类型来解决此问题。 But note that you are not using the result of collect(Collectors.toList()) but just printing the original, unaffected List . 但是请注意,您不是在使用collect(Collectors.toList())的结果,而只是打印未受影响的原始List On the other hand, you don't need the List when the array is given: 另一方面,给出数组时,您不需要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));

For printing without changing the array you can also use the following alternative 对于不更改阵列的打印,您也可以使用以下替代方法

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);

This sorts the groups instead of the individual values and prints identical values as often as they've been counted. 这将对组进行排序,而不是对单个值进行排序,并按计数的频率打印相同的值。

you need to add a type witness, minor compiler weakness: 您需要添加一个类型见证者,较小的编译器弱点:

 intList.stream()
        .sorted(Comparator.comparing((Integer x) -> frequencyMap.get(x))
                          .thenComparing(Comparator.naturalOrder()))
        .forEachOrdered(System.out::println);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM