我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
我对Java比较陌生,经常发现需要对值进行Map<Key,Value>排序。
由于这些值不是唯一的,我发现自己将keySet转换为一个数组,并使用自定义比较器通过数组排序对该数组进行排序,该比较器根据与该键关联的值进行排序。
有没有更简单的方法?
当前回答
如果您有重复的密钥,并且只有一小部分数据(<1000),并且您的代码不是性能关键型的,则可以执行以下操作:
Map<String,Integer> tempMap=new HashMap<String,Integer>(inputUnsortedMap);
LinkedHashMap<String,Integer> sortedOutputMap=new LinkedHashMap<String,Integer>();
for(int i=0;i<inputUnsortedMap.size();i++){
Map.Entry<String,Integer> maxEntry=null;
Integer maxValue=-1;
for(Map.Entry<String,Integer> entry:tempMap.entrySet()){
if(entry.getValue()>maxValue){
maxValue=entry.getValue();
maxEntry=entry;
}
}
tempMap.remove(maxEntry.getKey());
sortedOutputMap.put(maxEntry.getKey(),maxEntry.getValue());
}
inputUnsortedMap是代码的输入。
变量sortedOutputMap将在迭代时按降序包含数据。要更改顺序,只需在if语句中将>更改为<。
不是最快的排序,但可以在没有任何附加依赖项的情况下完成任务。
其他回答
Java 8提供了一个新的答案:将条目转换为流,并使用Map中的比较器组合符。条目:
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));
上面看到的LinkedHashMap按插入顺序迭代条目。
或打印到System.out:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);
您可以尝试Guava的多功能地图:
TreeMap<Integer, Collection<String>> sortedMap = new TreeMap<>(
Multimaps.invertFrom(Multimaps.forMap(originalMap),
ArrayListMultimap.<Integer, String>create()).asMap());
因此,您将获得从原始值到对应于它们的键集合的映射。即使同一值有多个键,也可以使用此方法。
我的解决方案是一种非常简单的方法,使用大多数给定的API。我们使用Map的特性通过entrySet()方法将其内容导出为Set。我们现在有一个包含Map.Entry对象的集合。
好的,集合不携带订单,但我们可以将内容放入ArrayList。它现在有一个随机顺序,但无论如何我们都会对它进行排序。
由于ArrayList是一个集合,所以我们现在使用Collections.sort()方法来将秩序带入混乱。因为我们的Map.Entry对象没有实现我们需要的那种比较,所以我们提供了一个自定义比较器。
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("Z", "E");
map.put("G", "A");
map.put("D", "C");
map.put("E", null);
map.put("O", "C");
map.put("L", "D");
map.put("Q", "B");
map.put("A", "F");
map.put(null, "X");
MapEntryComparator mapEntryComparator = new MapEntryComparator();
List<Entry<String,String>> entryList = new ArrayList<>(map.entrySet());
Collections.sort(entryList, mapEntryComparator);
for (Entry<String, String> entry : entryList) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
对于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));
从…起http://www.programmersheaven.com/download/49349/download.aspx
private static <K, V> Map<K, V> sortByValue(Map<K, V> map) {
List<Entry<K, V>> list = new LinkedList<>(map.entrySet());
Collections.sort(list, new Comparator<Object>() {
@SuppressWarnings("unchecked")
public int compare(Object o1, Object o2) {
return ((Comparable<V>) ((Map.Entry<K, V>) (o1)).getValue()).compareTo(((Map.Entry<K, V>) (o2)).getValue());
}
});
Map<K, V> result = new LinkedHashMap<>();
for (Iterator<Entry<K, V>> it = list.iterator(); it.hasNext();) {
Map.Entry<K, V> entry = (Map.Entry<K, V>) it.next();
result.put(entry.getKey(), entry.getValue());
}
return result;
}