我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
当前回答
您可以尝试Guava的多功能地图:
TreeMap<Integer, Collection<String>> sortedMap = new TreeMap<>(
Multimaps.invertFrom(Multimaps.forMap(originalMap),
ArrayListMultimap.<Integer, String>create()).asMap());
因此,您将获得从原始值到对应于它们的键集合的映射。即使同一值有多个键,也可以使用此方法。
其他回答
如果您的Map值实现Comparable(例如String),那么这应该会起作用
Map<Object, String> map = new HashMap<Object, String>();
// Populate the Map
List<String> mapValues = new ArrayList<String>(map.values());
Collections.sort(mapValues);
如果映射值本身没有实现Comparable,但您有一个Comparable实例可以对它们进行排序,请将最后一行替换为:
Collections.sort(mapValues, comparable);
这可以用java8非常容易地实现
public static LinkedHashMap<Integer, String> sortByValue(HashMap<Integer, String> map) {
List<Map.Entry<Integer, String>> list = new ArrayList<>(map.entrySet());
list.sort(Map.Entry.comparingByValue());
LinkedHashMap<Integer, String> sortedMap = new LinkedHashMap<>();
list.forEach(e -> sortedMap.put(e.getKey(), e.getValue()));
return sortedMap;
}
我建议使用Arrays.sort,而不是像某些人那样使用Collections.ort。实际上Collections.ort的作用是这样的:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
它只调用列表上的array,然后使用Arrays.sort。这样,所有映射条目将被复制三次:一次从映射复制到临时列表(无论是LinkedList还是ArrayList),然后复制到临时数组,最后复制到新映射。
我的解决方案省略了这一步,因为它不会创建不必要的LinkedList。以下是代码,通用友好,性能最佳:
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map)
{
@SuppressWarnings("unchecked")
Map.Entry<K,V>[] array = map.entrySet().toArray(new Map.Entry[map.size()]);
Arrays.sort(array, new Comparator<Map.Entry<K, V>>()
{
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<K, V>();
for (Map.Entry<K, V> entry : array)
result.put(entry.getKey(), entry.getValue());
return result;
}
对于Java 8,您可以使用streams api以一种明显不那么冗长的方式来实现:
Map<K, V> sortedMap = map.entrySet().stream()
.sorted(Entry.comparingByValue())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
HashMap<String,Long>的最简单的暴力排序HashMap方法:您可以复制粘贴它,然后这样使用:
public class Test {
public static void main(String[] args) {
HashMap<String, Long> hashMap = new HashMap<>();
hashMap.put("Cat", (long) 4);
hashMap.put("Human", (long) 2);
hashMap.put("Dog", (long) 4);
hashMap.put("Fish", (long) 0);
hashMap.put("Tree", (long) 1);
hashMap.put("Three-legged-human", (long) 3);
hashMap.put("Monkey", (long) 2);
System.out.println(hashMap); //{Human=2, Cat=4, Three-legged-human=3, Monkey=2, Fish=0, Tree=1, Dog=4}
System.out.println(sortHashMap(hashMap)); //{Cat=4, Dog=4, Three-legged-human=3, Human=2, Monkey=2, Tree=1, Fish=0}
}
public LinkedHashMap<String, Long> sortHashMap(HashMap<String, Long> unsortedMap) {
LinkedHashMap<String, Long> result = new LinkedHashMap<>();
//add String keys to an array: the array would get sorted, based on those keys' values
ArrayList<String> sortedKeys = new ArrayList<>();
for (String key: unsortedMap.keySet()) {
sortedKeys.add(key);
}
//sort the ArrayList<String> of keys
for (int i=0; i<unsortedMap.size(); i++) {
for (int j=1; j<sortedKeys.size(); j++) {
if (unsortedMap.get(sortedKeys.get(j)) > unsortedMap.get(sortedKeys.get(j-1))) {
String temp = sortedKeys.get(j);
sortedKeys.set(j, sortedKeys.get(j-1));
sortedKeys.set(j-1, temp);
}
}
}
// construct the result Map
for (String key: sortedKeys) {
result.put(key, unsortedMap.get(key));
}
return result;
}
}