4

TreeMap で最も高い 3 つの値を見つけようとしています。一応やっているコードを書いたのですが、もっと効率の良い方法があれば教えていただきたいです。基本的に、テキストの各単語をテキストに表示される回数とともに TreeMap に保存しています。次に、コンパレータを使用して値を並べ替えています。次に、並べ替え後の最大値である最後の 3 つの値に到達するまで、新しく作成された Map を繰り返し処理し、それらを出力します。大きなテキストを使用するので、これはあまり良い方法ではありません。これが私のコードです:

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

2 に答える 2

3

ハッシュ マップを使用して頻度をカウントし、それらすべてをループして上位 3 つを選択します。この方法で比較を最小限に抑え、並べ替える必要はありません。選択アルゴリズムを使用する

-edit、ウィキペディアのページには、選択アルゴリズムのさまざまな実装が詳しく説明されています。具体的には、制限付きの優先度キューを使用し、サイズを 3 に設定します。派手にキューをヒープなどとして実装しないでください。配列を使用するだけです。

于 2012-05-20T19:14:47.407 に答える
1

スケーラブルで超高速のソリューションが本当に必要な場合は、Lucene をご覧ください。この種のことは、朝ベッドから出る前に行うものです。すべてのテキストを含む 1 つのドキュメントにインデックスを付けて、上位の用語を取得するだけです。を含む上位の用語を見つけるためのコードがどこかにあります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))))
于 2012-05-20T19:59:53.590 に答える