java 使用哈希Map按值然后按键对列表进行排序

cl25kdpy  于 2023-03-06  发布在  Java
关注(0)|答案(3)|浏览(136)

我有一个数字列表,我试图按频率排序,如果频率相同,它们应该按升序排序。我首先创建一个列表的Map,其中键代表每个数字,值代表它们的频率。然后使用比较器从那里排序。我已经尝试了几种不同的方法,但完全卡住了。请帮助,并为任何语法不佳提前道歉。与过去的代码,我已经得到了一个结果,将不会按键排序,如果值是相同的,但现在我只是得到一个错误。

items = [42, 5, 17, 42, 42, 17, 5, 42]

public static void sortByFreq(List<Integer> items) {
    Map<Integer, Integer> counter = new HashMap<Integer, Integer>();
    for (int i = 0; i < items.size(); i++) {
        if (counter.containsKey(items.get(i))) {
            counter.put(items.get(i), counter.get(items.get(i)) + 1);
        } else {
            counter.put(items.get(i), 1);
        }
    }
    Comparator<Map.Entry<Integer, Integer>> comp = new Comparator<Map.Entry<Integer, Integer>>() {
        @Override
        public int compare(Map.Entry<Integer, Integer> a, Map.Entry<Integer, Integer> b) {

            if (a.getValue().compareTo(b.getValue()) == 0) {
                return a.getKey().compareTo(b.getKey());
            }
            else {
                return a.getValue().compareTo(b.getValue());
            }
        }
    };

    Collections.sort(items, comp);

Expected Result : [42, 42, 42, 42, 5, 5, 17, 17]
Error received: java: no suitable method found for sort(java.util.List<java.lang.Integer>,java.util.Comparator<java.util.Map.Entry<java.lang.Integer,java.lang.Integer>>)
    method java.util.Collections.<T>sort(java.util.List<T>) is not applicable
      (cannot infer type-variable(s) T
        (actual and formal argument lists differ in length))
    method java.util.Collections.<T>sort(java.util.List<T>,java.util.Comparator<? super T>) is not applicable
      (inference variable T has incompatible bounds
        equality constraints: java.lang.Integer
        upper bounds: java.util.Map.Entry<java.lang.Integer,java.lang.Integer>,java.lang.Object)
mcvgt66p

mcvgt66p1#

Comparator的参数应该是Integer s,因为List包含的就是Integer s。你需要调用counter.get来获得要比较的频率。使用Comparator.comparing.thenComparing可以更简单地实现这一点。

Map<Integer, Long> counter = items.stream().collect(
                  Collectors.groupingBy(Function.identity(), Collectors.counting()));
items.sort(Comparator.comparing((Integer i) -> counter.get(i))
     .reversed().thenComparing(Function.identity()));
mmvthczy

mmvthczy2#

对每个值进行计数,然后按计数进行排序

List<Integer> items = List.of( 42, 5, 17, 42, 42, 17, 5, 42 );
Map<Integer, Long> counts = items.stream()
    .collect( Collectors.toMap(
        Function.identity(),
        v -> 1L,
        Long::sum
    ));
List<Integer> sorted = items.stream()
    .sorted( Comparator
        .comparingLong( a -> counts.getOrDefault( a, 0L ) )
        .reversed()
    )
    .toList();
System.out.println( sorted );
f87krz0w

f87krz0w3#

下面是处理流的一种方法:

List<Integer> sorted = items.stream()
        .collect(Collectors.groupingBy(n -> n, Collectors.summingInt(n -> 1)))
        .entrySet()
        .stream()
        .sorted(Map.Entry.comparingByKey())
        .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
        .map(e -> Collections.nCopies(e.getValue(), e.getKey()))
        .flatMap(List::stream)
        .collect(Collectors.toList());

第一个collect生成一个频率图,然后我们按键排序条目,再按值排序,这样就得到了一个主要按值排序的流(即频率),其次是键。它等效于comparing(Entry::getValue).reversed().thenComparing(Entry::getKey),但避免了混乱的泛型参数最后,我们将每个条目扩展回重复项的子列表,并将它们扁平化为最终结果列表。

相关问题