2012-05-20 4 views
4

Я пытаюсь найти три самых высоких значения в TreeMap. Я написал код, который это делает, но я хотел бы спросить, можете ли вы предложить более эффективный способ. В основном я сохраняю каждое слово своего текста в TreeMap вместе с количеством раз, которое оно появляется в тексте. Затем я использую компаратор для сортировки значений. Затем я повторяю новую карту до тех пор, пока не получу последние три значения, которые являются самыми высокими значениями после сортировки и распечатывают их. Я собираюсь использовать большие тексты, так что это не очень хороший способ. Вот мой код:получить три самых высоких значения в TreeMap

class Text{ 
    public static void main(String args[]) throws FileNotFoundException, IOException{ 
     final File textFile = new File("C://FileIO//cinderella.txt"); 
     final BufferedReader in = new BufferedReader(new FileReader(textFile));        
     final TreeMap<String, Integer> frequencyMap = new TreeMap<String, Integer>(); 

     String currentLine; 
     while ((currentLine = in.readLine()) != null) { 
      currentLine = currentLine.toLowerCase(); 
      final StringTokenizer parser = new StringTokenizer(currentLine, " \t\n\r\f.,;:!?'"); 
      while (parser.hasMoreTokens()) { 
       final String currentWord = parser.nextToken(); 
       Integer frequency = frequencyMap.get(currentWord); 
       if (frequency == null) { 
        frequency = 0; 
       } 
       frequencyMap.put(currentWord, frequency + 1); 
      } 
     } 

     System.out.println("This the unsorted Map: "+frequencyMap); 

     Map sortedMap = sortByComparator(frequencyMap); 
     int i = 0; 
     int max=sortedMap.size(); 
     StringBuilder query= new StringBuilder(); 

     for (Iterator it = sortedMap.entrySet().iterator(); it.hasNext();) { 
      Map.Entry<String,Integer> entry = (Map.Entry<String,Integer>) it.next(); 
      i++; 
      if(i<=max && i>=(max-2)){ 
       String key = entry.getKey(); 
       //System.out.println(key); 
       query.append(key); 
       query.append("+"); 
      } 
     } 
     System.out.println(query); 
    } 

    private static Map sortByComparator(TreeMap unsortMap) { 
     List list = new LinkedList(unsortMap.entrySet()); 

     //sort list based on comparator 
     Collections.sort(list, new Comparator() { 
      public int compare(Object o1, Object o2) { 
       return ((Comparable) ((Map.Entry) (o1)).getValue()) 
         .compareTo(((Map.Entry) (o2)).getValue()); 
      } 
     }); 

     //put sorted list into map again 
     Map sortedMap = new LinkedHashMap(); 
     for (Iterator it = list.iterator(); it.hasNext();) { 
      Map.Entry entry = (Map.Entry)it.next(); 
      sortedMap.put(entry.getKey(), entry.getValue()); 

     } 
     return sortedMap; 
    } 
} 

ответ

3

Я бы рассчитывать частоты с хэш-карты, а затем цикл над ними все, выбирая верхнюю 3. Вы минимизировать Сравнения этот путь, и никогда не придется сортировать. Используйте Selection Algorithm

-edit, страница wikipedia содержит множество различных вариантов реализации алгоритма выбора. Чтобы быть конкретным, просто используйте ограниченную очередь приоритетов и установите размер равным 3. Не получайте фантазии и не выполняйте очередь как кучу или что-то еще. просто используйте массив.

+0

Избегайте имеет смысл, потому что вы «собираетесь использовать большие тексты» _. Поэтому, если вам не нужна сортировка для дальнейшей обработки, я бы выбрал это решение. – Kai

+0

Благодарим вас за этот совет. Именно так я изменил свой код. – curious

1

Если вы действительно хотите масштабируемое и быстродействующее решение, пожалуйста, взгляните на Lucene, так как это то, что он делает, прежде чем вставать с постели по утрам. Все, что вам нужно сделать, это проиндексировать один документ со всем текстом, а затем получить верхние термины. Там где-то есть код, чтобы найти термины высшего ранга, включая PriorityQueue. Я получил копию в Clojure, даже если вы не знаете языка, вы можете подобрать соответствующие вызовы API из него (или, по крайней мере, Google от них и найти версию Java): сортировка

(defn top-terms [n] 
    (let [f "field-name" 
     tenum (-> ^IndexSearcher searcher .getIndexReader (.terms (Term. f))) 
     q (proxy [org.apache.lucene.util.PriorityQueue] [] 
      (lessThan [a b] (< (a 0) (b 0))))] 
    (-> org.apache.lucene.util.PriorityQueue 
     (.getDeclaredMethod "initialize" (into-array [Integer/TYPE])) 
     (doto (.setAccessible true)) (.invoke q (into-array [(Integer/valueOf n)]))) 
    (loop [] (when (= (-> tenum .term .field) f) 
       (.insertWithOverflow q [(.docFreq tenum) (.term tenum)]) 
       (when (.next tenum) (recur)))) 
    (loop [terms nil] (if (> (.size q) 0) (recur (conj terms (.pop q))) terms)))) 
+0

Спасибо Марко. Я посмотрю на Lucene, но для моей нынешней цели карта Hash была более подходящей и простой :) – curious

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