在Java中,按照列表中出现的次数排序大量单词列表(10,000-20,000)的最佳/最简单方法是什么?我尝试了一个基本的实现,但是我得到了内存运行时错误,所以我需要一种更有效的方法。你会建议什么?
ArrayList<String> occuringWords = new ArrayList<String>();
ArrayList<Integer> numberOccur = new ArrayList<Integer>();
String temp;
int count;
for(int i = 0; i < finalWords.size(); i++){
temp = finalWords.get(i);
count = 0;
for(int j = 0; j < finalWords.size(); j++){
if(temp.equals(finalWords.get(j))){
count++;
finalWords.remove(j);
j--;
}
}
if(numberOccur.size() == 0){
numberOccur.add(count);
occuringWords.add(temp);
}else{
for(int j = 0; j < numberOccur.size(); j++){
if(count>numberOccur.get(j)){
numberOccur.add(j, count);
occuringWords.add(j, temp);
}
}
}
}
其中finalWords是所有字符串的列表。我不得不将每个单词出现的次数存储在一个单独的arraylist中,因为我想不出更好的方法来保持它们配对而不将每个单词作为单独的对象。
答案 0 :(得分:9)
根据出现次数构建HashMap<String, Integer>
映射字。第一次看到一个单词时将其添加到地图并将计数设置为1.此后,如果地图中已存在该单词,则会增加计数。
这将会快得多,因为您只需迭代一次单词列表。这是O( n )和O( n 2 )之间的区别,对于大字典而言,这将是一个巨大的差异。
最后,您可以获取单词列表并按计数对其进行排序。您必须将它们从地图中取出并将它们添加到单独的数据结构中才能执行此操作。 (提示:您可以将TreeSet
与自定义Comparator
一起使用,根据频率对单词进行比较。或者,不太优雅,将其添加到List
,然后sort列表,再次使用自定义Comparator
。)
答案 1 :(得分:4)
您正在从谷歌收藏中看到Multiset。该数据结构完全是为了支持您的用例而构建的。你需要做的就是用你的文字填充它。它会保持你的频率
答案 2 :(得分:2)
为什么这么复杂?您基本上需要以下内容:
复杂性为O(n log n)。
答案 3 :(得分:1)
您是否考虑过除了hashmap之外还使用String interning? 字符串实习意味着所有相同的字符串使用相同的内存位置以节省内存。 根据答案Sort a Map<Key, Value> by values (Java),请参阅以下内容:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeMap;
public class WordOccurSortExample {
public static void main(String[] args) {
new WordOccurSortExample();
}
public WordOccurSortExample()
{
ArrayList<String> occuringWords = new ArrayList<String>();
occuringWords.add("Menios".intern());
occuringWords.add("Menios".intern());
occuringWords.add("Menios".intern());
occuringWords.add("Menios".intern());
occuringWords.add("Moo".intern());
occuringWords.add("Moo".intern());
occuringWords.add("Moo".intern());
occuringWords.add("Moo".intern());
occuringWords.add("Moo".intern());
occuringWords.add("Boo".intern());
occuringWords.add("Boo".intern());
occuringWords.add("Boo".intern());
HashMap<String, Integer> occurances = new HashMap<String, Integer>();
Iterator<String> it = occuringWords.iterator();
String word;
Integer count;
while(it.hasNext())
{
word = it.next();
if((count = occurances.get(word))==null)
occurances.put(word, 1);
else
occurances.put(word, new Integer(count+1));
}
ValueComparator bvc = new ValueComparator(occurances);
TreeMap<String,Integer> sorted_map = new TreeMap<String,Integer>(bvc);
System.out.println("unsorted map: "+occuringWords);
sorted_map.putAll(occurances);
System.out.println("results: "+sorted_map);
}
class ValueComparator implements Comparator<String> {
HashMap<String, Integer> base;
public ValueComparator(HashMap<String, Integer> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with equals.
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
}
}
答案 4 :(得分:0)
public List<String> countOccurences(ArrayList<String> list){
HashMap<String, Integer> hm = new HashMap<String, Integer>();
for (String s:list) {
Integer i = hm.get(s);
if (i == null){
i = 0;
}
i++;
hm.put(s, i);
}
List<String> mapKeys = new ArrayList<String>(hm.keySet());
List<Integer> mapValues = new ArrayList<Integer>(hm.values());
HashMap<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
TreeSet<Integer> sortedSet = new TreeSet<Integer>(mapValues);
Object[] sortedArray = sortedSet.toArray();
int size = sortedArray.length;
for (int i=0; i<size; i++){
sortedMap.put(mapKeys.get(mapValues.indexOf(sortedArray[i])),
(Double)sortedArray[i]);
}
return new ArrayList<String>(sorted.keyset());
}
答案 5 :(得分:-2)
按字母顺序排序单词的最简单方法。但你也可以通过另一个单词中存在多少个字母来表达。