如何从地图中获取按值排序然后按键排序的条目列表

How get a List of Entries sorted by Value and then by Key from a Map

我的问题是如何根据值和键对 Map 内容进行排序并得到 List 个条目作为结果?

首先,条目需要按降序[=34]排序=],然后如果 values 发生冲突,则按 key in 对它们进行排序也降序

给定 Map 的示例 :

Map<String,Integer> data = new HashMap();
data.put("a",10);
data.put("b",3);
data.put("c",10);

预期订单:

["c", 10], ["a",10], ["b",3]
public class Person implements Comparable<Person>{

    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Person person) {
        if(this.age!= person.age){
            return person.age.compareTo(this.age);
        } else {
         return person.name.compareTo(this.name);
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public static void main(String argsp[]){
        Map<String,Integer> data = new HashMap();
        data.put("a",10);
        data.put("b",3);
        data.put("c",10);

        List<Person> collect = data.entrySet().stream().map(entry -> new Person(entry.getKey(), entry.getValue())).collect(Collectors.toList());
        Collections.sort(collect);
        collect.stream().forEach(person-> System.out.println(person));

    Collection<Map.Entry<String,Integer>> result  = collect.stream().map(person -> 
            new AbstractMap.SimpleEntry<String, Integer>(person.name, person.age)).collect(Collectors.toList());


    }
}

结果:

Person{name='c', age=10}
Person{name='a', age=10}
Person{name='b', age=3}

使用流 api 和自定义 Comparator

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {

  static Map<String, Integer> createTestMap() {
    Map<String, Integer> data = new HashMap();
    data.put("a", 10);
    data.put("b", 3);
    data.put("c", 10);
    return data;
  }

  public static void main(String[] args) {
    var sorted = createTestMap().entrySet().stream()
        .sorted(Comparator
            .comparing(Map.Entry<String, Integer>::getValue)
            .thenComparing(Map.Entry<String, Integer>::getKey).reversed())
        .collect(Collectors.toList());
    for (var kv : sorted) {
      System.out.println(
          String.format("%s\t%s", kv.getKey(), kv.getValue()));
    }
  }
  }
}

写一个 Comparator<Map.Entry<String,Integer>> 根据您的规则比较地图条目。从地图中获取 new ArrayList<>(map.entrySet()) 的条目列表。使用 Collections.sort(list, comparator).

对该列表进行排序

为此你需要定义一个 Comparator.

您可以为此目的使用静态方法,这些方法作为 Java 8 的增强添加到 ComparatorMap.Entry 接口.

Map.Entry接口的两种方法comparingByValue() and comparingByKey()都会为生成一个比较器 valueskeys 分别。为了获得 降序 reversed() 方法需要应用于它们。

两个比较器都与thenComparing()方法链接在一起。

Comparator<Map.Entry<String, Integer>> valDescThenKeyDesc =
       Map.Entry.<String, Integer>comparingByValue().reversed()
           .thenComparing(Map.Entry.<String, Integer>comparingByKey().reversed());

请注意,编译器无法推断 comparingByValue()comparingByKey() 参数的正确类型基于 only 基于 comparator.

的结果类型

因此,comparingByValue()comparingByKey()都需要显式地提供通用类型信息<String, Integer>keys

如果一开始看起来很难理解,您可以将其分成单独的行(在这种情况下,类型推断工作正常):

Comparator<Map.Entry<String, Integer>> byValDesc =
       Map.Entry.comparingByValue().reversed();

Comparator<Map.Entry<String, Integer>> byKeyDesc =
       Map.Entry.comparingByKey().reversed();

Comparator<Map.Entry<String, Integer>> valDescThenKeyDesc =
       byValDesc.thenComparing(byKeyDesc);

for more information on how to build comparators with Java 8 methods, take a look at this tutorial

下一步是创建一个排序的条目列表

为此,您可以通过将 条目集 传递给构造函数来手动创建 List 条目,然后将方法 sort() 应用于它,或者通过使用 Stream API

为了用流来实现它,首先,我们需要获得一个条目流。通过传递给定的 比较器 应用 sorting() 操作,并通过应用终端操作 collect() 将结果收集到 list 中。

public static List<Map.Entry<String, Integer>> getMapEntryList(Map<String,Integer> data,
                                                               Comparator<Map.Entry<String, Integer>> comparator) {
    return data.entrySet().stream()
            .sorted(comparator)
            .collect(Collectors.toList());
}

main()

public static void main(String[] args) {
    Map<String,Integer> data = Map.of("a",10, "b",3,"c",10);

    Comparator<Map.Entry<String, Integer>> valDescThenKeyDesc =
            Map.Entry.<String, Integer>comparingByValue().reversed()
                    .thenComparing(Map.Entry.<String, Integer>comparingByKey().reversed());

    List<Map.Entry<String, Integer>> result = getMapEntryList(data, valDescThenKeyDesc);
    
    System.out.println(result);
}

输出

[c=10, a=10, b=3]