Java 使用 TreeMap 和 Comparator 按值对 HashMap 进行排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19579923/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sorting HashMap by value using a TreeMap and Comparator
提问by seeker
Im using the following code to create a hashmap and then sort the values in the hashmap by using a treemap and a comparator. However, the output is rather unexpected. So any thoughts as to what Im doing wrong would be helpful
我使用以下代码创建哈希图,然后使用树图和比较器对哈希图中的值进行排序。然而,输出是相当出乎意料的。所以任何关于我做错了什么的想法都会有所帮助
Code
代码
public static void main(String[] args) {
System.out.println("Most freq"+mostFreq(" i me hello hello hello me"));
}
public static String[] mostFreq(String str){
if ((str==null)||( str.trim().equalsIgnoreCase("")))
return null;
String[] arr = new String[10];
String[] words= str.split(" ");
Map <String,Integer> map = new HashMap<String,Integer>();
for (String word :words)
{
int count =0;
if (map.containsKey(word))
{
count= map.get(word);
map.put(word, count+1);
}
else
map.put(word, 1);
}
MyComparator comp= new MyComparator(map);
Map<String,Integer> newMap= new TreeMap(comp);
newMap.putAll(map);
Iterator it= newMap.entrySet().iterator();
while (it.hasNext())
{
Map.Entry pairs = (Map.Entry) it.next();
System.out.println("Key "+pairs.getKey()+"-- value"+pairs.getValue());
}
return arr;
}
Here's the comparator
这是比较器
package samplecodes;
import java.util.Comparator;
import java.util.Map;
public class MyComparator implements Comparator {
Map map;
public MyComparator(Map map){
this.map=map;
}
@Override
public int compare(Object o1, Object o2) {
return ((Integer)map.get(o1) >(Integer)map.get(o2)? (Integer)map.get(o1):(Integer)map.get(o2));
}
}
And the output is of the form
和输出的形式
me-2
hello-3
i-3
回答by Robin Krahl
Please check the JavaDoc of compare
: You do not return the bigger value, but -1
for o1
< o2
, 0
for o1
= o2
and 1
for o1
> o2
. So you could write:
请检查的JavaDoc的compare
:你不回更大的价值,但-1
对于o1
< o2
, 0
用于o1
=o2
和1
为o1
> o2
。所以你可以写:
@Override
public int compare(Object o1, Object o2) {
return ((Integer) map.get(o1)).compareTo((Integer) map.get(o2);
}
回答by Sage
The Java Docof TreeMap
clearly states that:
在Java文档中TreeMap
明确指出:
A Red-Black tree based NavigableMap implementation. The map is sorted according to the natural ordering of its keys
基于红黑树的 NavigableMap 实现。地图根据其键的自然顺序进行排序
we should not violate this rule by using TreeMap
to sort by values.
我们不应该使用TreeMap
按值排序来违反此规则。
However to sort by values, we can do the following:
但是要按值排序,我们可以执行以下操作:
- Create a
LinkedList
of entries of themap
- using
Collection.sort
to sort the entries - Inserting the sorted entries to a
LinkedHashMap
: keeps the keys in the order they are inserted, which is currently sorted on natural ordering. Return the
LinkedHashMap
as the sortedmap
.public static <K extends Comparable,V extends Comparable> Map<K,V> sortByValues(Map<K,V> map){ List<Map.Entry<K,V>> entries = new LinkedList<Map.Entry<K,V>>(map.entrySet()); Collections.sort(entries, new Comparator<Map.Entry<K,V>>() { @Override public int compare(Entry<K, V> o1, Entry<K, V> o2) { return o1.getValue().compareTo(o2.getValue()); } }); Map<K,V> sortedMap = new LinkedHashMap<K,V>(); for(Map.Entry<K,V> entry: entries){ sortedMap.put(entry.getKey(), entry.getValue()); } return sortedMap; } }
- 创建一个
LinkedList
条目map
- 使用
Collection.sort
的条目进行排序 - 将已排序的条目插入到 a
LinkedHashMap
: 保持键的插入顺序,当前按自然顺序排序。 返回
LinkedHashMap
排序后的map
。public static <K extends Comparable,V extends Comparable> Map<K,V> sortByValues(Map<K,V> map){ List<Map.Entry<K,V>> entries = new LinkedList<Map.Entry<K,V>>(map.entrySet()); Collections.sort(entries, new Comparator<Map.Entry<K,V>>() { @Override public int compare(Entry<K, V> o1, Entry<K, V> o2) { return o1.getValue().compareTo(o2.getValue()); } }); Map<K,V> sortedMap = new LinkedHashMap<K,V>(); for(Map.Entry<K,V> entry: entries){ sortedMap.put(entry.getKey(), entry.getValue()); } return sortedMap; } }
Reference:Sorting Map by value
参考:按值排序地图
回答by Adrian Shum
What you are doing is really a misuse of tools.
您所做的实际上是滥用工具。
I believe what you need to do is:
我相信你需要做的是:
- Have a list/array of input words (still fine that you get it by splitting the input string)
- Create a Map to store the word as key, and frequency as value
- Have a collection of unique words, then sort the collection base on the the frequency
- When you are doing the output, traverse the sorted unique word list, for each element, get the frequency from the frequencyMap, and output the word + frequency.
- 有一个输入单词的列表/数组(通过拆分输入字符串来获得它仍然很好)
- 创建一个 Map 以将单词存储为键,将频率存储为值
- 有一个独特的词的集合,然后根据频率对集合进行排序
- 做输出的时候,遍历排序后的唯一词列表,对于每个元素,从frequencyMap中获取频率,输出词+频率。
Of course you can still make use of something like a TreeSet and use frequency as key, but you should have list of words as the value of this map (aka Multi-Map), instead of writing a problematic comparator which do not follow the contract of Comparator: http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html#compare%28T,%20T%29Both your original implementation and the one in comment of one of the answers does not comply with the rule of sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y
(The original one is even worse).
当然,您仍然可以使用 TreeSet 之类的东西并使用频率作为键,但是您应该将单词列表作为此映射(又名 Multi-Map)的值,而不是编写一个不遵守约定的有问题的比较器比较器的:http: //docs.oracle.com/javase/6/docs/api/java/util/Comparator.html#compare%28T,%20T%29您的原始实现和其中之一的评论中的一个答案不符合规则sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y
(原来的更糟)。
some code snippet just for giving you hints:
一些代码片段只是为了给你提示:
List<String> words = ....;
Map<String, Integer> wordFrequencyMap = new HashMap<String, Integer>();
// iterate words and update wordFrequencyMap accordingly
List<String> uniqueWords = new ArrayList<String>(new HashSet<String>(words));
Collections.sort(uniqueWords, new WordFrequencyComparator<String>(wordFrequencyMap));
for (String w : uniqueWords) {
System.out.println("word : " + w + " frequency : " + wordFrequencyMap.get(w));
}
The missing part shouldn't be anything difficult.
缺失的部分应该不难。