TreeMap 按值排序

新手上路,请多包涵

我想编写一个比较器,让我可以按值而不是默认的自然顺序对 TreeMap 进行排序。

我尝试过这样的事情,但无法找出问题所在:

 import java.util.*;

class treeMap {
    public static void main(String[] args) {
        System.out.println("the main");
        byValue cmp = new byValue();
        Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
        map.put("de",10);
        map.put("ab", 20);
        map.put("a",5);

        for (Map.Entry<String,Integer> pair: map.entrySet()) {
            System.out.println(pair.getKey()+":"+pair.getValue());
        }
    }
}

class byValue implements Comparator<Map.Entry<String,Integer>> {
    public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
        if (e1.getValue() < e2.getValue()){
            return 1;
        } else if (e1.getValue() == e2.getValue()) {
            return 0;
        } else {
            return -1;
        }
    }
}

我想我要问的是:我可以得到一个 Map.Entry 传递给比较器吗?

原文由 vito huang 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 482
2 个回答

您不能让 TreeMap 本身对值进行排序,因为这违反了 SortedMap 规范:

A Map 进一步提供了对其 的 _总排序_。

但是,使用外部集合,您始终可以根据需要对 Map.entrySet() 进行排序,无论是通过键、值,还是两者的组合(!!)。

这是一种返回A SortedSet Map Comparable Map.Entry 一个通用方法。

 static <K,V extends Comparable<? super V>>
SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
    SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
        new Comparator<Map.Entry<K,V>>() {
            @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                int res = e1.getValue().compareTo(e2.getValue());
                return res != 0 ? res : 1;
            }
        }
    );
    sortedEntries.addAll(map.entrySet());
    return sortedEntries;
}

现在您可以执行以下操作:

     Map<String,Integer> map = new TreeMap<String,Integer>();
    map.put("A", 3);
    map.put("B", 2);
    map.put("C", 1);

    System.out.println(map);
    // prints "{A=3, B=2, C=1}"
    System.out.println(entriesSortedByValues(map));
    // prints "[C=1, B=2, A=3]"

请注意,如果您尝试修改 SortedSet 本身或内部的 Map.Entry ,则会发生奇怪的事情,因为这不再是原始地图的“视图”,例如 entrySet() 是。

一般而言,按值对地图条目进行排序的需求是非典型的。


关于 == 的注意事项 Integer

您原来的比较器比较 Integer 使用 == 。这几乎总是错误的,因为 ==Integer 操作数是引用相等,而不是值相等。

     System.out.println(new Integer(0) == new Integer(0)); // prints "false"!!!

相关问题

原文由 polygenelubricants 发布,翻译遵循 CC BY-SA 3.0 许可协议

多基因润滑剂的回答 几乎 是完美的。但它有一个重要的错误。它不会处理值相同的映射条目。

这段代码:…

 Map<String, Integer> nonSortedMap = new HashMap<String, Integer>();
nonSortedMap.put("ape", 1);
nonSortedMap.put("pig", 3);
nonSortedMap.put("cow", 1);
nonSortedMap.put("frog", 2);

for (Entry<String, Integer> entry  : entriesSortedByValues(nonSortedMap)) {
    System.out.println(entry.getKey()+":"+entry.getValue());
}

会输出:

 ape:1
frog:2
pig:3

注意我们的母牛是如何消失的,因为它与我们的猿猴共享值“1”:哦!

此代码修改解决了该问题:

 static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
        SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
            new Comparator<Map.Entry<K,V>>() {
                @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                    int res = e1.getValue().compareTo(e2.getValue());
                    return res != 0 ? res : 1; // Special fix to preserve items with equal values
                }
            }
        );
        sortedEntries.addAll(map.entrySet());
        return sortedEntries;
    }

原文由 Olof Larsson 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏