按值的树图比较器

时间:2019-11-13 19:18:12

标签: java sorting hashmap comparator treemap

SortedMap<Integer, Long> newMap = new TreeMap(new MyComparator(result));
newMap.putAll(result);
System.out.println("new map ---> " + newMap);

MyComparator.java

package com.example.admin.app;

import java.util.Comparator;
import java.util.Map;

class MyComparator implements Comparator {

    Map map;
    public MyComparator(Map map){
        this.map = map;
    }

    public int compare (Object o1, Object o2) {
        return ((Long) map.get(o2)).compareTo((Long) map.get(o1));
    }
}

使用树形图比较器时,如果2个键的值相同,则比较器仅考虑第一个值,而忽略第二个值。

例如:未排序的地图-> {2 = 93085,1 = 93254,4 = 92928,9 = 93164,8 = 93085}

我写的代码的实际结果:{1 = 93254,9 = 93164,8 = 93085,4 = 92928}

我需要输出--{1 = 93254,9 = 93164,8 = 93085,2 = 93085,4 = 92928}

由于键2和8具有相同的值(93085),所以我只能得到一个。有人帮忙。

1 个答案:

答案 0 :(得分:1)

当比较器报告键相等时,TreeMap的一个属性就是将键视为相等(并且映射通常不支持多个相等键)。

the specification说:

  

…已排序的映射使用其compareTo(或compare)方法执行所有键比较,因此,从已排序的映射的角度来看,此方法认为相等的两个键是相等的。

如果要防止键之间没有顺序时按键消失,则必须添加一个辅助顺序,以便在主顺序认为它们相等时使用。由于您的地图首先具有可比较的键,因此您可以利用其自然顺序来获得所需的结果:

class MyComparator implements Comparator<Integer> {
    final Map<Integer, Long> map;
    public MyComparator(Map<Integer, Long> map){
        this.map = map;
    }
    public int compare(Integer o1, Integer o2) {
        int c = Long.compare(map.get(o2), map.get(o1));
        return c != 0? c: o2.compareTo(o1);
    }
}
Map<Integer, Long> result = new HashMap<>();
result.put(2, 93085L);
result.put(1, 93254L);
result.put(4, 92928L);
result.put(9, 93164L);
result.put(8, 93085L);

SortedMap<Integer, Long> newMap = new TreeMap<>(new MyComparator(result));
newMap.putAll(result);
// new map ---> {1=93254, 9=93164, 8=93085, 2=93085, 4=92928}
System.out.println("new map ---> " + newMap);

或者,您可以使用LinkedHashMap来维护插入顺序并使用已排序的列表来填充它:

List<Integer> list = new ArrayList<>(result.keySet());
Collections.sort(list, new MyComparator(result));
Map<Integer, Long> newMap = new LinkedHashMap<>();
for(Integer i: list) newMap.put(i, result.get(i));
System.out.println("new map ---> " + newMap);

这两种方法都会生成具有所需迭代顺序的映射。哪个更合适取决于以后的使用方式。

由于对列表进行排序不会消除重复项,因此它也可以与您的初始比较器一起使用,尽管我会使其类型安全:

class MyComparator implements Comparator<Integer> {
    final Map<?, Long> map;
    public MyComparator(Map<?, Long> map){
        this.map = map;
    }
    public int compare(Integer o1, Integer o2) {
        return Long.compare(map.get(o2), map.get(o1));
    }
}

但是随后,没有指定具有相同值的条目的相对顺序。