我试图在TreeMap中找到三个最高值。我编写了一个代码,但是我想问一下你是否可以提出一种更有效的方法。 基本上,我在TreeMap中保存文本的每个单词以及它在文本中出现的次数。然后我使用比较器对值进行排序。然后我迭代新创建的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;
}
}
答案 0 :(得分:3)
我会使用哈希映射计算频率,然后将它们全部循环,选择前3个。您可以通过这种方式最小化比较,而不必排序。使用Selection Algorithm
-edit,维基百科页面详述了选择算法的许多不同实现。具体来说,只需使用有界优先级队列,并将大小设置为3.不要花哨并将队列实现为堆或任何东西。只需使用数组。
答案 1 :(得分:1)
如果您真的想要一个可扩展且闪电般快速的解决方案,请看看Lucene,因为这种事情是它在早上起床前所做的事情。您所要做的就是使用所有文本索引单个文档,然后检索排名靠前的术语。在某个地方有一段代码可以找到排名靠前的术语,涉及PriorityQueue
。我在Clojure中有一份副本,即使你不懂语言,你也可以从中收集相关的API调用(至少谷歌由他们收集并找到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))))