按值对HashMap进行排序[重复]
Posted
技术标签:
【中文标题】按值对HashMap进行排序[重复]【英文标题】:Sorting HashMap by values [duplicate] 【发布时间】:2011-12-28 11:52:54 【问题描述】:我需要根据存储在其中的值对我的HashMap
进行排序。 HashMap
包含存储在手机中的联系人姓名。
我还需要在对值进行排序后立即自动对键进行排序,或者您可以说键和值绑定在一起,因此值的任何更改都应反映在键中。
HashMap<Integer,String> map = new HashMap<Integer,String>();
map.put(1,"froyo");
map.put(2,"abby");
map.put(3,"denver");
map.put(4,"frost");
map.put(5,"daisy");
需要的输出:
2,abby;
5,daisy;
3,denver;
4,frost;
1,froyo;
【问题讨论】:
【参考方案1】:基本上你不会。 HashMap
基本上是无序的。您可能在排序中看到的任何模式都应该不被依赖。
有诸如TreeMap
之类的排序映射,但它们传统上是按键排序而不是按值排序。按值排序相对不常见——尤其是多个键可以具有相同的值。
您能否为您正在尝试做的事情提供更多背景信息?如果您真的只存储键的数字(作为字符串),那么 SortedSet
(例如 TreeSet
)可能适合您?
或者,您可以将两个单独的集合存储在一个类中以同时更新它们?
【讨论】:
例如,对图像上出现的颜色进行排序。它必须很快,因为我们可以有 max_int 颜色。 @RafaelSanches:尚不清楚您评论的上下文是什么。在这种情况下 map 会是什么?你可能想问一个新问题。 我只是举一个例子,它有助于以最高效的方式按值对 hashmap 进行排序。 我们可以使用这样的东西吗?Arrays.sort(hm.values().toArray());
@VedPrakash:是的,如果您使用总分作为键存储地图,您不应该期望能够存储两个总分相同的值。我建议您提出一个新问题,详细说明您所面临的问题。【参考方案2】:
假设是 Java,你可以像这样对 hashmap 进行排序:
public LinkedHashMap<Integer, String> sortHashMapByValues(
HashMap<Integer, String> passedMap)
List<Integer> mapKeys = new ArrayList<>(passedMap.keySet());
List<String> mapValues = new ArrayList<>(passedMap.values());
Collections.sort(mapValues);
Collections.sort(mapKeys);
LinkedHashMap<Integer, String> sortedMap =
new LinkedHashMap<>();
Iterator<String> valueIt = mapValues.iterator();
while (valueIt.hasNext())
String val = valueIt.next();
Iterator<Integer> keyIt = mapKeys.iterator();
while (keyIt.hasNext())
Integer key = keyIt.next();
String comp1 = passedMap.get(key);
String comp2 = val;
if (comp1.equals(comp2))
keyIt.remove();
sortedMap.put(key, val);
break;
return sortedMap;
只是一个启动示例。这种方式更有用,因为它对 HashMap 进行排序并保留重复值。
【讨论】:
查看编辑后的版本。我不认为 collections.sort(mapvalues) 会解决问题 这段代码已经根据keys排列了hashmap。我想要的是:(2,abby; 5,daisy; 3,denver; 4,frost; 1,froyo;)ie值是根据排列的到他们的首字母缩写,变化会反映在键中...... 我稍微编辑了您的代码,它可以按预期工作。非常感谢。 请注意,由于在两个 while 循环中重复查找值,给定算法的时间复杂度为 O(n^2)。将 Entry Set 转换为 List,然后根据比较器对 List 进行排序将是一种更有效的解决方案。 这种方法的主要问题是由于嵌套的 while 循环,它需要二次时间。有更好的答案,比如来自 Rais Alarm 的优秀答案。【参考方案3】:试试下面的代码,它对我来说很好。您可以选择升序和降序
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class SortMapByValue
public static boolean ASC = true;
public static boolean DESC = false;
public static void main(String[] args)
// Creating dummy unsorted map
Map<String, Integer> unsortMap = new HashMap<String, Integer>();
unsortMap.put("B", 55);
unsortMap.put("A", 80);
unsortMap.put("D", 20);
unsortMap.put("C", 70);
System.out.println("Before sorting......");
printMap(unsortMap);
System.out.println("After sorting ascending order......");
Map<String, Integer> sortedMapAsc = sortByComparator(unsortMap, ASC);
printMap(sortedMapAsc);
System.out.println("After sorting descindeng order......");
Map<String, Integer> sortedMapDesc = sortByComparator(unsortMap, DESC);
printMap(sortedMapDesc);
private static Map<String, Integer> sortByComparator(Map<String, Integer> unsortMap, final boolean order)
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(unsortMap.entrySet());
// Sorting the list based on values
Collections.sort(list, new Comparator<Entry<String, Integer>>()
public int compare(Entry<String, Integer> o1,
Entry<String, Integer> o2)
if (order)
return o1.getValue().compareTo(o2.getValue());
else
return o2.getValue().compareTo(o1.getValue());
);
// Maintaining insertion order with the help of LinkedList
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list)
sortedMap.put(entry.getKey(), entry.getValue());
return sortedMap;
public static void printMap(Map<String, Integer> map)
for (Entry<String, Integer> entry : map.entrySet())
System.out.println("Key : " + entry.getKey() + " Value : "+ entry.getValue());
编辑:版本 2
使用了新的 java 特性,例如 stream for-each 等
如果值相同,地图将按键排序
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public class SortMapByValue
private static boolean ASC = true;
private static boolean DESC = false;
public static void main(String[] args)
// Creating dummy unsorted map
Map<String, Integer> unsortMap = new HashMap<>();
unsortMap.put("B", 55);
unsortMap.put("A", 20);
unsortMap.put("D", 20);
unsortMap.put("C", 70);
System.out.println("Before sorting......");
printMap(unsortMap);
System.out.println("After sorting ascending order......");
Map<String, Integer> sortedMapAsc = sortByValue(unsortMap, ASC);
printMap(sortedMapAsc);
System.out.println("After sorting descending order......");
Map<String, Integer> sortedMapDesc = sortByValue(unsortMap, DESC);
printMap(sortedMapDesc);
private static Map<String, Integer> sortByValue(Map<String, Integer> unsortMap, final boolean order)
List<Entry<String, Integer>> list = new LinkedList<>(unsortMap.entrySet());
// Sorting the list based on values
list.sort((o1, o2) -> order ? o1.getValue().compareTo(o2.getValue()) == 0
? o1.getKey().compareTo(o2.getKey())
: o1.getValue().compareTo(o2.getValue()) : o2.getValue().compareTo(o1.getValue()) == 0
? o2.getKey().compareTo(o1.getKey())
: o2.getValue().compareTo(o1.getValue()));
return list.stream().collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> b, LinkedHashMap::new));
private static void printMap(Map<String, Integer> map)
map.forEach((key, value) -> System.out.println("Key : " + key + " Value : " + value));
【讨论】:
不错的答案,使用集合工具以正确的方式编写。 针对我的问题进行了尝试,发现需要对您的比较器逻辑进行轻微修改,您没有检查应该添加的空检查,因为地图值可以包含空元素。 有用且清晰的答案。 我发现这个解决方案简单易懂。 如果我想按照value
的长度来排序,比如String呢?【参考方案4】:
package SortedSet;
import java.util.*;
public class HashMapValueSort
public static void main(String[] args)
final Map<Integer, String> map = new HashMap<Integer,String>();
map.put(4,"Mango");
map.put(3,"Apple");
map.put(5,"Orange");
map.put(8,"Fruits");
map.put(23,"Vegetables");
map.put(1,"Zebra");
map.put(5,"Yellow");
System.out.println(map);
final HashMapValueSort sort = new HashMapValueSort();
final Set<Map.Entry<Integer, String>> entry = map.entrySet();
final Comparator<Map.Entry<Integer, String>> comparator = new Comparator<Map.Entry<Integer, String>>()
@Override
public int compare(Map.Entry<Integer, String> o1, Map.Entry<Integer, String> o2)
String value1 = o1.getValue();
String value2 = o2.getValue();
return value1.compareTo(value2);
;
final SortedSet<Map.Entry<Integer, String>> sortedSet = new TreeSet(comparator);
sortedSet.addAll(entry);
final Map<Integer,String> sortedMap = new LinkedHashMap<Integer, String>();
for(Map.Entry<Integer, String> entry1 : sortedSet )
sortedMap.put(entry1.getKey(),entry1.getValue());
System.out.println(sortedMap);
【讨论】:
不错的一个。谢谢你。【参考方案5】:public static TreeMap<String, String> sortMap(HashMap<String, String> passedMap, String byParam)
if(byParam.trim().toLowerCase().equalsIgnoreCase("byValue"))
// Altering the (key, value) -> (value, key)
HashMap<String, String> newMap = new HashMap<String, String>();
for (Map.Entry<String, String> entry : passedMap.entrySet())
newMap.put(entry.getValue(), entry.getKey());
return new TreeMap<String, String>(newMap);
return new TreeMap<String, String>(passedMap);
【讨论】:
【参考方案6】:在 Java 8 中:
Map<Integer, String> sortedMap =
unsortedMap.entrySet().stream()
.sorted(Entry.comparingByValue())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
【讨论】:
这个排序可以倒置吗?我需要的值从大到小 @AquariusPower 查看docs.oracle.com/javase/8/docs/api/java/util/… 的reversed
方法您可以将其应用于comparingByValue()
返回的比较器
Entry.comparingByValue().reversed()
的返回与.sorted(...)
预期的参数不兼容:(,我最终得到了一个反向循环for
超过.entrySet().toArray()
,可能是演员可以解决它,我需要更多时间来测试:)
@AquariusPower 你不需要强制转换,只需给编译器一个泛型类型的提示:Entry.<Integer, String>comparingByValue().reversed()
而这种编程方式正是我讨厌jdk8的原因。 getKey,getValue, (e1,e2)->e1, ::new... 然后我们可以在火边召唤“wooloh loh”并召唤夜之精灵...【参考方案7】:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
public class CollectionsSort
/**
* @param args
*/`enter code here`
public static void main(String[] args)
// TODO Auto-generated method stub
CollectionsSort colleciotns = new CollectionsSort();
List<combine> list = new ArrayList<combine>();
HashMap<String, Integer> h = new HashMap<String, Integer>();
h.put("nayanana", 10);
h.put("lohith", 5);
for (Entry<String, Integer> value : h.entrySet())
combine a = colleciotns.new combine(value.getValue(),
value.getKey());
list.add(a);
Collections.sort(list);
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
public class combine implements Comparable<combine>
public int value;
public String key;
public combine(int value, String key)
this.value = value;
this.key = key;
@Override
public int compareTo(combine arg0)
// TODO Auto-generated method stub
return this.value > arg0.value ? 1 : this.value < arg0.value ? -1
: 0;
public String toString()
return this.value + " " + this.key;
【讨论】:
请在回答之前确保您的代码运行正确。还可以考虑添加 cmets,以便提问者更好地理解您的答案。【参考方案8】:找到了解决方案,但如果地图尺寸较大,则不确定性能,这对正常情况很有用。
/**
* sort HashMap<String, CustomData> by value
* CustomData needs to provide compareTo() for comparing CustomData
* @param map
*/
public void sortHashMapByValue(final HashMap<String, CustomData> map)
ArrayList<String> keys = new ArrayList<String>();
keys.addAll(map.keySet());
Collections.sort(keys, new Comparator<String>()
@Override
public int compare(String lhs, String rhs)
CustomData val1 = map.get(lhs);
CustomData val2 = map.get(rhs);
if (val1 == null)
return (val2 != null) ? 1 : 0;
else if (val1 != null) && (val2 != null))
return = val1.compareTo(val2);
else
return 0;
);
for (String key : keys)
CustomData c = map.get(key);
if (c != null)
Log.e("key:"+key+", CustomData:"+c.toString());
【讨论】:
其中的错字应该是 else if ((val1 != null) && (val2 != null)) return val1.compareTo(val2); 在比较方法中【参考方案9】:如果您只需要最终结果,可以使用 temp TreeMap 作为一种简单的解决方案:
TreeMap<String, Integer> sortedMap = new TreeMap<String, Integer>();
for (Map.Entry entry : map.entrySet())
sortedMap.put((String) entry.getValue(), (Integer)entry.getKey());
这将使您的字符串作为 sortedMap 的键进行排序。
【讨论】:
这只有在所有整数值都是唯一的情况下才有效——否则,你会覆盖字符串。【参考方案10】:package com.naveen.hashmap;
import java.util.*;
import java.util.Map.Entry;
public class SortBasedonValues
/**
* @param args
*/
public static void main(String[] args)
HashMap<String, Integer> hm = new HashMap<String, Integer>();
hm.put("Naveen", 2);
hm.put("Santosh", 3);
hm.put("Ravi", 4);
hm.put("Pramod", 1);
Set<Entry<String, Integer>> set = hm.entrySet();
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(
set);
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>()
public int compare(Map.Entry<String, Integer> o1,
Map.Entry<String, Integer> o2)
return o2.getValue().compareTo(o1.getValue());
);
for (Entry<String, Integer> entry : list)
System.out.println(entry.getValue());
【讨论】:
我尝试执行此代码,使用import java.util.Map.Entry;'
运行良好但相同的代码无法使用import java.util.*;
运行,据我所知,后者包括前者。那为什么会报错呢?
简洁优雅【参考方案11】:
map.entrySet().stream()
.sorted((k1, k2) -> -k1.getValue().compareTo(k2.getValue()))
.forEach(k -> System.out.println(k.getKey() + ": " + k.getValue()));
【讨论】:
对我来说最易读的解决方案并完成工作,例如运行按值排序的 HashMap 简洁明了;优雅易读。 这按地图值的降序打印,我怎样才能强制它升序? 从 k1.getValue() @Rohan 中删除减号【参考方案12】:我扩展了一个 TreeMap 并覆盖了 entrySet() 和 values() 方法。键和值需要是可比较的。
关注代码:
public class ValueSortedMap<K extends Comparable, V extends Comparable> extends TreeMap<K, V>
@Override
public Set<Entry<K, V>> entrySet()
Set<Entry<K, V>> originalEntries = super.entrySet();
Set<Entry<K, V>> sortedEntry = new TreeSet<Entry<K, V>>(new Comparator<Entry<K, V>>()
@Override
public int compare(Entry<K, V> entryA, Entry<K, V> entryB)
int compareTo = entryA.getValue().compareTo(entryB.getValue());
if(compareTo == 0)
compareTo = entryA.getKey().compareTo(entryB.getKey());
return compareTo;
);
sortedEntry.addAll(originalEntries);
return sortedEntry;
@Override
public Collection<V> values()
Set<V> sortedValues = new TreeSet<>(new Comparator<V>()
@Override
public int compare(V vA, V vB)
return vA.compareTo(vB);
);
sortedValues.addAll(super.values());
return sortedValues;
单元测试:
public class ValueSortedMapTest
@Test
public void basicTest()
Map<String, Integer> sortedMap = new ValueSortedMap<>();
sortedMap.put("A",3);
sortedMap.put("B",1);
sortedMap.put("C",2);
Assert.assertEquals("B=1, C=2, A=3", sortedMap.toString());
@Test
public void repeatedValues()
Map<String, Double> sortedMap = new ValueSortedMap<>();
sortedMap.put("D",67.3);
sortedMap.put("A",99.5);
sortedMap.put("B",67.4);
sortedMap.put("C",67.4);
Assert.assertEquals("D=67.3, B=67.4, C=67.4, A=99.5", sortedMap.toString());
【讨论】:
这不符合Map
接口。 entrySet()
的正确实现是:“返回此映射中包含的映射的集合视图。集合由映射支持,因此对映射的更改会反映在集合中,反之亦然反之亦然。" values()
也是如此。
真棒正是我要找的东西以上是关于按值对HashMap进行排序[重复]的主要内容,如果未能解决你的问题,请参考以下文章