Java TreeMap按Pair<Integer,String>的Integer键排序实现咨询
嘿,刚好碰到过类似的需求,先给你理清楚一个核心点:TreeMap本质是基于键(也就是你这里的String类型)来排序的,它自带的比较器只能拿到键做比较,没办法直接访问对应的值,所以没法让TreeMap自动按值里的Integer来维护顺序。不过有几种靠谱的方案能实现你的需求,我给你拆解一下:
方案1:先排序再用LinkedHashMap存(适合静态/修改少的场景)
如果你的Map不需要频繁添加或修改元素,或者每次修改后愿意重新排个序,那这个方案最省事:先把所有键值对放到列表里,按Pair的Integer排好序,再塞进LinkedHashMap里——它会严格保持插入的顺序。
代码示例(假设你用的是Apache Commons的Pair,或者自己写的Pair类,只要有获取Integer的方法就行):
// 先初始化你的TreeMap并添加元素 TreeMap<String, Pair<Integer, String>> originalMap = new TreeMap<>(); originalMap.put("apple", Pair.of(5, "red")); originalMap.put("banana", Pair.of(2, "yellow")); // 把entry转成列表,按Pair里的Integer排序 List<Map.Entry<String, Pair<Integer, String>>> entryList = new ArrayList<>(originalMap.entrySet()); entryList.sort(Comparator.comparing(entry -> entry.getValue().getKey())); // 放入LinkedHashMap保持排序后的顺序 Map<String, Pair<Integer, String>> sortedMap = new LinkedHashMap<>(); for (var entry : entryList) { sortedMap.put(entry.getKey(), entry.getValue()); }
方案2:自定义一个按值排序的Map(适合动态修改频繁的场景)
如果需要Map每次添加/删除元素后都自动保持按Pair的Integer排序,那可以自己封装一个Map的实现,内部用TreeSet来存条目——因为TreeSet可以自定义比较器,直接比较值里的Integer:
public class ValueSortedMap<K, V extends Pair<Integer, ?>> extends AbstractMap<K, V> { private final Map<K, V> backingMap = new HashMap<>(); private final Set<Map.Entry<K, V>> sortedEntries; public ValueSortedMap() { // 先按Pair的Integer排序,Integer相同时用键保证唯一性(避免重复) sortedEntries = new TreeSet<>(Comparator.comparing((Map.Entry<K, V> entry) -> entry.getValue().getKey()) .thenComparing(Map.Entry::getKey)); } @Override public V put(K key, V value) { // 先移除旧的条目(如果存在) sortedEntries.removeIf(entry -> entry.getKey().equals(key)); // 添加新条目到排序集合里 sortedEntries.add(new AbstractMap.SimpleEntry<>(key, value)); // 同时更新底层的HashMap return backingMap.put(key, value); } @Override public Set<Map.Entry<K, V>> entrySet() { return Collections.unmodifiableSet(sortedEntries); } @Override public V get(Object key) { return backingMap.get(key); } }
用的时候直接实例化这个类就行,添加元素后遍历就是按Pair的Integer排序的:
ValueSortedMap<String, Pair<Integer, String>> myMap = new ValueSortedMap<>(); myMap.put("cat", Pair.of(3, "meow")); myMap.put("dog", Pair.of(1, "woof")); // 遍历myMap会先输出dog(Integer=1),再输出cat(Integer=3)
关于Pair子类的疑问
完全没必要给Pair创建子类来实现比较器!不管你用的是第三方库的Pair(比如Apache Commons、JavaFX的)还是自己写的,只要能通过get方法拿到里面的Integer,就可以直接用Comparator.comparing()来提取值做比较,非常灵活。
比如你自己写了个Pair类:
public class MyPair<K, V> { private K first; private V second; // 构造器、getFirst()、getSecond()... }
那比较器可以直接这么写:
Comparator<Map.Entry<String, MyPair<Integer, String>>> comparator = Comparator.comparing(entry -> entry.getValue().getFirst());
总结一下:静态数据选方案1,简单高效;动态频繁修改选方案2,自动维护排序。不用折腾Pair子类,直接用比较器搞定就行~
内容的提问来源于stack exchange,提问作者tw123

