我是 Java 的新手,经常发现我需要在Map<Key, Value>
上对Map<Key, Value>
进行排序。
由于值不是唯一的,我发现自己将keySet
转换为array
,并通过数组排序对该数组进行排序,并使用自定义比较器对与键关联的值进行排序。
有没有更简单的方法?
这是一个通用友好版本:
public class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Entry<K, V>> list = new ArrayList<>(map.entrySet());
list.sort(Entry.comparingByValue());
Map<K, V> result = new LinkedHashMap<>();
for (Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
}
此代码可以以多种方式中断。如果您打算使用提供的代码,请务必阅读注释以了解其含义。例如,不能再通过其密钥检索值。 ( get
总是返回null
。)
它似乎比上述所有内容容易得多。使用 TreeMap 如下:
public class Testing {
public static void main(String[] args) {
HashMap<String, Double> map = new HashMap<String, Double>();
ValueComparator bvc = new ValueComparator(map);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
map.put("A", 99.5);
map.put("B", 67.4);
map.put("C", 67.4);
map.put("D", 67.3);
System.out.println("unsorted map: " + map);
sorted_map.putAll(map);
System.out.println("results: " + sorted_map);
}
}
class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with
// equals.
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
}
输出:
unsorted map: {D=67.3, A=99.5, B=67.4, C=67.4}
results: {D=67.3, B=67.4, C=67.4, A=99.5}
Java 8 提供了一个新的答案:将条目转换为流,并使用 Map.Entry 中的比较器组合器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue());
这将允许您使用按值的升序排序的条目。如果要降序值,只需反转比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
如果值不具有可比性,则可以传递显式比较器:
Stream<Map.Entry<K,V>> sorted =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(comparator));
然后,您可以继续使用其他流操作来使用数据。例如,如果您想要新地图中的前 10 名:
Map<K,V> topTen =
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(10)
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
或者打印到System.out
:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);