2009-12-01 74 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) 

}