使用TreeMap和Comparator按值对HashMap进行排序

时间:2013-10-25 02:03:19

标签: java sorting collections hashmap

我使用以下代码创建一个hashmap,然后使用树形图和比较器对hashmap中的值进行排序。但是,输出相当出乎意料。 因此,任何关于我做错事的想法都会有所帮助

代码

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;
}

这是比较器

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));
    }

}

输出的格式为

me-2
hello-3
i-3

3 个答案:

答案 0 :(得分:3)

请检查compare的JavaDoc:您没有返回更大的值,-1表示o1&lt; o2 0o1o2 = 1o1o2&gt; @Override public int compare(Object o1, Object o2) { return ((Integer) map.get(o1)).compareTo((Integer) map.get(o2); } 。所以你可以写:

{{1}}

答案 1 :(得分:1)

TreeMap的{​​{3}}明确指出:

  

基于红黑树的NavigableMap实现。地图已排序   根据

的自然顺序

我们不应该使用TreeMap按值排序来违反此规则。

但是,要按值排序,我们可以执行以下操作:

  1. 创建LinkedList
  2. map条目
  3. 使用Collection.sort对条目进行排序
  4. 将已排序的条目插入LinkedHashMap:按照插入顺序保存密钥,当前按自然顺序排序。
  5. 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;
    }
    
    }
    
  6. 参考: Java Doc

答案 2 :(得分:0)

你所做的实际上是滥用工具。

我相信你需要做的是:

  1. 有一个输入单词的列表/数组(通过拆分输入字符串,你可以得到它)
  2. 创建地图以将单词存储为键,将频率存储为值
  3. 拥有一系列独特的单词,然后根据频率对集合进行排序
  4. 当您进行输出时,遍历排序的唯一单词列表,对于每个元素,从frequencyMap获取频率,并输出单词+频率。
  5. 当然你仍然可以使用像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的规则(原来的更糟糕)。

    一些代码片段只是为了给你提示:

    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));
    }
    

    缺少的部分不应该是困难的。