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

Java 比较器,用于按频率排序,无需创建比较器实现类,java,sorting,java-8,comparator,Java,Sorting,Java 8,Comparator,只是想知道我们是否可以使用Java8根据重复数字的频率对列表进行排序,而无需编写自定义的比较器类 我需要根据给定的整数的频率,然后按照自然的数字顺序对其进行排序 我在比较器上出错了 以下是我尝试的代码: 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, L

只是想知道我们是否可以使用Java8根据重复数字的频率对列表进行排序,而无需编写自定义的比较器类

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

我在比较器上出错了

以下是我尝试的代码:

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

PS:为了避免列表,在第一行中使用了数组。添加多行,以便清楚地理解。

您需要添加类型见证,编译器的小缺点:

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

您需要添加类型见证,较小的编译器缺陷:

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

不幸的是,当链接Comparator.comparingfrequencyMap::get与ComparingComparator.naturalOrder时,Java的类型推断无法识别被比较对象的类型。由于Map.get的方法签名是getObject,编译器将Comparator推断为Comparator.comparingfrequencyMap::get的结果类型

可以通过插入显式类型来修复此问题。但请注意,您使用的不是collectCollectors.toList的结果,而是打印原始的未受影响的列表。另一方面,在给定数组时,不需要列表:

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的类型推断无法识别被比较对象的类型。comparingfrequencyMap::使用ComparingComparator.naturalOrder获取。由于Map.get的方法签名是getObject,编译器将Comparator推断为Comparator.comparingfrequencyMap::get的结果类型

可以通过插入显式类型来修复此问题。但请注意,您使用的不是collectCollectors.toList的结果,而是打印原始的未受影响的列表。另一方面,在给定数组时,不需要列表:

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

这将对组而不是单个值进行排序,并按计数的频率打印相同的值。

此处打印的是原始intList,而不是collect创建的排序列表。使用新列表更新了sysout。此处打印的是原始intList,不是collect创建的排序列表。使用新列表更新了sysout。Comparator.ComparingIt不应该在这里帮助我们吗?@Lino comparingLong,但这是不够的,因为问题是Map.get的参数类型是Object,即使Map具有类型Map。但是,在使用Comparator时,可以保留方法引用。comparingLongfrequencyMap::get…Comparator.ComparingInIt帮助我们吗?@Lino comparingLong,但这是不够的,因为问题是Map.get的参数类型是Object,即使Map具有类型Map。但是在使用Comparator时可以保留方法引用…