【问题标题】:Treemap comparator by value按值的树形图比较器
【发布时间】:2020-03-09 15:54:37
【问题描述】:
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),我只得到一个。有人请帮忙。

【问题讨论】:

  • 你是什么意思I'm getting only one你能显示代码吗?
  • 欢迎来到stackoverflow!为了让我们帮助您,您可以发布您正在使用的比较器代码吗?
  • 显示您的代码。
  • Comparator 使用的 TreeMap 比较的是键,而不是值。您的代码中一定有其他原因导致此问题。
  • @JacobG。我认为如果比较器返回 0,TreeMap 会将其解释为相同的键值,并将之前的值替换为新的值

标签: java sorting hashmap comparator treemap


【解决方案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));
    }
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多