2009-12-01 68 views
4

我正在寫一個Java程序,用於解析文本文件中的所有單詞,然後將它們添加到HashMap中。我需要計算文件中包含多少個不同的單詞。我還需要計算出最高的計數單詞。 HashMap由映射到一個整數的每個單詞組成,該整數表示單詞出現的次數。類似HashMap但排序?

有沒有像HashMap這樣可以幫我排序呢?

+0

沒有標準的集合,我知道的是解決這個問題。那裏有幾個詞?如果你可以忍受開銷,最容易實現的就是使用HashMap,然後把這些單詞與出現在列表中並對其進行排序。 – Buhb 2009-12-01 20:07:02

+1

想想吧,我在大學裏得到了這個確切的任務,我們必須在nlog(n)中解決它。我上面的建議管理着這一點。 – Buhb 2009-12-01 20:12:51

+0

你想按字還是按頻率對地圖進行排序? – PSpeed 2009-12-01 21:57:23

回答

1

它看起來像commons collections庫中的TreeBag類可能會做你想做的。它跟蹤一個對象有多少個副本添加到包中,並按count的升序對它們進行排序。要獲得最高計數項目,請調用last()方法。有一點需要注意的是,commons collections的東西還沒有更新到使用泛型,所以你可能會得到大量的編譯器警告。

+0

或者您可以在Google Collections中搜索一些使用泛型的特殊地圖。 – 2009-12-01 20:15:59

+0

重新閱讀文檔。我相信在這種情況下,Bag仍然會按照「關鍵」或詞語排序。不是數量。你可以引用另外的文檔嗎? – z5h 2009-12-01 20:16:21

+0

你可能是對的,我解釋了最後一種方法的描述,意思是說它返回了最大計數的項目,但考慮到可選比較器的上下文,它可能僅僅意味着自然順序最大的那個。 – Orclev 2009-12-01 20:26:12

5

手工的方式來做到這一點是如下:

  • wordcount字段創建一個複合字計數類。
  • 爲按類別排序的類創建比較器。
  • 完成填充HashMap後,創建一個由HashMap中的值創建的新WordCount對象列表。
  • 使用比較器對列表進行排序。
+0

正是我所想的。 – Esko 2009-12-01 20:15:00

5

你可以使用一個HashMultiset從google-collections

import com.google.common.collect.*; 
import com.google.common.collect.Multiset.Entry; 

... 

    final Multiset<String> words = HashMultiset.create(); 
    words.addAll(...); 

    Ordering<Entry<String>> byIncreasingCount = new Ordering<Entry<String>>() { 
    @Override public int compare(Entry<String> a, Entry<String> b) { 
     // safe because count is never negative 
     return left.getCount() - right.getCount(); 
    } 
    }); 

    Entry<String> maxEntry = byIncreasingCount.max(words.entrySet()) 
    return maxEntry.getElement(); 

編輯:哎呀,我還以爲你只想要一個最常見的詞。但它聽起來像你想要的幾個最常見的 - 所以,你可以用sortedCopy替換max,現在你有一個所有條目的順序列表。

要查找的不同單詞的數量:words.elementSet().size()

+0

+1:對於Google收藏集! – 2009-12-05 17:35:58

-2
  • YourBean implements Comparable<YourBean>
  • 方法的compareTo:通過詞的編號順序
  • TreeMap的,而不是HashMap的
+2

這個答案是非常不完整的... – 2009-12-01 20:33:50

+0

樹形圖不能按值排序!所以這不是正確的數據結構。 – 2012-02-22 12:25:14

0

爲計數,東東的Set中的單詞並計算完成後的大小。

對於最高值,迭代所有條目並保留具有最高值的鍵。

2

如果要按字排序Map,則TreeMap是Java內置答案。您可以確保您的Word對象是Comparable或提供自定義比較器。

SortedMap<Word,Integer> map = new TreeMap<Word,Integer>(); 
... 
for all words { 
    Integer count = map.get(word); 
    if (count == null) count = 0; 
    map.put(word, count+1); 
} 

如果你想按頻率排序,那麼在所有的單詞已經被計數之後,你會更好的做到這一點。排序後的集合不會通過外部更改讓他們的排序搞砸。按頻率排序需要其他人發佈的複合詞+計數對象。

+0

這使得地圖中的單詞按照字典順序排列,但不幸的是它們根本不按頻率排序。 – bchurchill 2013-01-14 11:31:32

0

你檢出了java.util.PriorityQueue嗎?PriorityQueue基本上是一個優先級映射到每個元素的列表(由非同步優先級堆實現)。每當你讀入一個新字符串時,如果它已經存在(對數時間),你可以將它加入或增加1。目前的支票是在線性時間,最後這將是非常容易使用。要獲得顯示頻率最高的數字,只需在每次完成時輪詢()!

編輯標準的PriorityQueue不允許您直接編輯優先級,因爲它需要一個比較器。你會用一個簡單的哈希實現什麼like this

2

更好這裏最普遍的回答的一個Groovy版本這個問題:

List leastCommon(Multiset myMultiset, Integer quantity) 
{ 

    Ordering<Multiset.Entry<String>> byIncreasingCount = new Ordering<Multiset.Entry<String>>() { 
     @Override public int compare(Multiset.Entry<String> a, Multiset.Entry<String> b) { 
      return a.getCount() - b.getCount() } 
    } 

    maxIndex = Math.min(quantity, myMultiset.entrySet().size() - 1) 
    return byIncreasingCount.sortedCopy(myMultiset.entrySet()).subList(0, maxIndex) 

} 

List mostCommon(Multiset myMultiset, Integer quantity) 
{ 

    Ordering<Multiset.Entry<String>> byDecreasingCount = new Ordering<Multiset.Entry<String>>() { 
     @Override public int compare(Multiset.Entry<String> a, Multiset.Entry<String> b) { 
      return b.getCount() - a.getCount() } 
    } 

    maxIndex = Math.min(quantity, myMultiset.entrySet().size() - 1) 
    return byDecreasingCount.sortedCopy(myMultiset.entrySet()).subList(0, maxIndex) 

}