根据Value来排序Map对象

By | 2022年3月8日

我们可以使用 TreeMap 类按其键对Map进行排序。 这个类使用起来非常方便。 但是,有时我们需要按其值对Map进行排序。 如何按值对映射进行排序是 Java 程序员最常问的问题。

自有方法

import java.util.Comparator;
import java.util.HashMap;
import java.util.TreeMap;
 
public class SortMapByValue {
 
	public static void main(String[] args) {
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("a", 10);
		map.put("b", 30);
		map.put("c", 50);
		map.put("d", 40);
		map.put("e", 20);
		System.out.println(map);
 
		TreeMap<String, Integer> sortedMap = sortMapByValue(map);  
		System.out.println(sortedMap);
	}
 
	public static TreeMap<String, Integer> sortMapByValue(HashMap<String, Integer> map){
		Comparator<String> comparator = new ValueComparator(map);
		//TreeMap is a map sorted by its keys. 
		//The comparator is used to sort the TreeMap by keys. 
		TreeMap<String, Integer> result = new TreeMap<String, Integer>(comparator);
		result.putAll(map);
		return result;
	}
}
// a comparator that compares Strings
class ValueComparator implements Comparator<String>{
 
	HashMap<String, Integer> map = new HashMap<String, Integer>();
 
	public ValueComparator(HashMap<String, Integer> map){
		this.map.putAll(map);
	}
 
	@Override
	public int compare(String s1, String s2) {
		if(map.get(s1) >= map.get(s2)){
			return -1;
		}else{
			return 1;
		}	
	}
}

在此解决方案中,我们使用 TreeMap 对Map进行排序。 创建 TreeMap 时,我们给它一个比较器。 比较器接受字符串并比较映射中给定字符串键的关联值。

该方法效果很好,但它仅适用于对字符串和整数对进行排序。 如果我们想用其他类型的键和值对映射进行排序,则需要对其进行重写。 因此,需要一个更通用的解决方案。

通用方案

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
 
public class Solution {
	public static void main(String[] args) {
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("a", 10);
		map.put("b", 30);
		map.put("c", 50);
		map.put("d", 40);
		map.put("e", 20);
		System.out.println(map);
 
		Map sortedMap = sortByValue(map);
		System.out.println(sortedMap);
	}
 
	public static Map sortByValue(Map unsortedMap) {
		Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
		sortedMap.putAll(unsortedMap);
		return sortedMap;
	}
 
}
 
class ValueComparator implements Comparator {
	Map map;
 
	public ValueComparator(Map map) {
		this.map = map;
	}
 
	public int compare(Object keyA, Object keyB) {
		Comparable valueA = (Comparable) map.get(keyA);
		Comparable valueB = (Comparable) map.get(keyB);
		return valueB.compareTo(valueA);
	}
}

这个方案就不局限与<String , Integer>的类型了,但是呢又有类型的安全隐患

泛型的方案

public class SortMapByValue {
 
	public static void main(String[] args) {
		// <String, Integer> Map
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("a", 10);
		map.put("b", 30);
		map.put("c", 50);
		map.put("d", 40);
		map.put("e", 20);
		System.out.println(map);
 
 
		Comparator<String> comparator = new ValueComparator<String, Integer>(map);
		TreeMap<String, Integer> result = new TreeMap<String, Integer>(comparator);
		result.putAll(map);
 
		System.out.println(result);
 
		// <Integer, Integer> Map
 
		HashMap<Integer, Integer> map2 = new HashMap<Integer, Integer>();
		map2.put(1, 10);
		map2.put(2, 30);
		map2.put(3, 50);
		map2.put(4, 40);
		map2.put(5, 20);
		System.out.println(map2);
 
		Comparator<Integer> comparator2 = new ValueComparator<Integer, Integer>(map2);
		TreeMap<Integer, Integer> result2 = new TreeMap<Integer, Integer>(comparator2);
		result2.putAll(map2);
 
		System.out.println(result2);
 
	}
 
}
// a comparator using generic type
class ValueComparator<K, V extends Comparable<V>> implements Comparator<K>{
 
	HashMap<K, V> map = new HashMap<K, V>();
 
	public ValueComparator(HashMap<K, V> map){
		this.map.putAll(map);
	}
 
	@Override
	public int compare(K s1, K s2) {
		return map.get(s1).compareTo(map.get(s2));//descending order	
	}
}

泛型的其他形式用法

public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
	List<Map.Entry<K, V>> list = new LinkedList<>(map.entrySet());
	Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
		@Override
		public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
			return (e1.getValue()).compareTo(e2.getValue());
		}
	});
 
	Map<K, V> result = new LinkedHashMap<>();
	for (Map.Entry<K, V> entry : list) {
		result.put(entry.getKey(), entry.getValue());
	}
 
	return result;
}

更简单的一种实现方式

LinkedList<Map.Entry<String, Integer>> list = new LinkedList<>(counter.entrySet());
Comparator<Map.Entry<String, Integer>> comparator = Comparator.comparing(Map.Entry::getValue);
Collections.sort(list, comparator.reversed());