【问题标题】:Comparator for sorting by frequency without Creating a Comparator implementation classComparator 用于按频率排序,无需创建 Comparator 实现类
【发布时间】:2019-03-22 13:04:58
【问题描述】:

只是想知道我们是否可以在不编写自定义比较器类的情况下使用 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());

预期的输出是

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

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

【问题讨论】:

  • 您在这里打印的是原始 intList,而不是 collect() 创建的排序列表。
  • 用新列表更新了系统输出。

标签: java sorting java-8 comparator


【解决方案1】:

不幸的是,当 Comparator.comparing(frequencyMap::get)thenComparing(Comparator.naturalOrder()) 链接时,Java 的类型推断无法识别比较对象的类型。由于Map.get的方法签名是get(Object),编译器推断Comparator&lt;Object&gt;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);

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

【讨论】:

    【解决方案2】:

    你需要添加一个类型见证,编译器的小弱点:

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

    【讨论】:

    • 不应该Comparator.comparingInt()在这里帮助我们吗?
    • @Lino comparingLong,但这还不够,因为问题是Map.get的参数类型是Object,即使地图的类型是Map&lt;Integer, Long&gt;。但是使用Comparator.&lt;Integer&gt;comparingLong(frequencyMap::get) …时可以保留方法引用
    猜你喜欢
    • 2020-03-19
    • 2011-08-04
    • 1970-01-01
    • 2021-09-18
    • 2013-07-20
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    相关资源
    最近更新 更多