2013-10-25 2 views
0

Im, используя следующий код для создания хэш-карты, а затем сортировку значений в хэш-карте с помощью treemap и компаратора. Однако выход довольно неожиданный. Так любые мысли относительно того, что Im делая неправильно было бы полезноСортировка HashMap по значению с помощью TreeMap и Comparator

Код

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 
+0

Ваш код не производит этот вывод. Вы уверены, что это тот, который вы используете? – Pshemo

+1

Также можно взглянуть на [how-to-sort-a-mapkey-value-on-the-values-in-java] (http://stackoverflow.com/questions/109383/how-to-sort-a -mapkey-value-on-the-values-in-java) – Pshemo

+1

много неприятного запаха в вашем коде: пожалуйста, добавьте тип generics type param для вашей карты, итератора и т. д. В 'mostFreq()' вы возвращаете 'arr', который это просто пустой массив String, который никогда не был затронут в методе. Я также отвечаю в ответ на вашу логическую проблему. –

ответ

3

Пожалуйста проверьте JavaDoc compare: вы не возвращаете большой Значение GER, но -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); 
} 
+0

Ах. Виноват. Но я думаю, что делать это вручную, т.е. 'if (o1 == o2) return 0; \t return (Integer) map.get (o1)> (Integer) map.get (o2)? 1: -1; 'является лучшим вариантом, когда вам нужна частота всех слов. использование 'compareTo', похоже, подавляет слова той же частоты. – KodeSeeker

+0

Вы правы; Я не думаю, что. Но в других случаях приятно делегировать сравнение с другими классами. ;) –

+0

@KodeSeeker Я думаю, что ваша логика в комментарии неправильная. IIRC 'compare()' должен быть «симметричным» http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html#compare%28T,%20T%29: sgn (сравнить (a, b)) следует вернуть -sgn (ср. (b, a)). Однако ваша логика не делает: если значение на карте для ключей «o1» и «o2» одинаково, оба сравнения (a, b) и сравнения (b, a) возвращают 1, что нарушает контракт. –

1

Java Doc из TreeMap четко говорится, что: осуществление NavigableMap на основе

Красно-черное дерево. Карта сортируется в соответствии с естественным порядком ее ключей

мы не должны нарушать это правило, используя TreeMap для сортировки по значениям.

Однако для сортировки значений, мы можем сделать следующее:

  1. Создание LinkedList записей в map
  2. используя Collection.sort для сортировки записей
  3. Вставки отсортированных элементов к LinkedHashMap: сохраняет ключи в том порядке, в котором они вставлены, которые в настоящее время сортируются по естественному заказу.
  4. Верните 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; 
    } 
    
    } 
    

Ссылка:Sorting Map by value

+0

Удивительный код. действительно собрал много вещей, в которых я был туман. Благодаря! – KodeSeeker

0

То, что вы делаете на самом деле злоупотребление инструментов.

Я считаю, что вам нужно сделать, это:

  1. есть список/массив входных слов (по-прежнему прекрасно, что вы получите его путем разделения входной строки)
  2. создать карту для хранения слова как ключ и частота как значение
  3. Имейте коллекцию уникальных слов, затем отсортируйте базу данных на частоте
  4. Когда вы делаете вывод, переходите отсортированный уникальный список слов для каждого элемента, получите частоту из frequencyMap, и вывести слово + частота.

Конечно, вы все равно можете использовать что-то вроде TreeSet и использовать частоту в качестве ключа, но у вас должен быть список слов как значение этой карты (aka 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)); 
} 

Недостающую часть не должна быть чем-то трудно.

Смежные вопросы