Java 如何获得地图中重复次数最多的5个元素?

Java 如何获得地图中重复次数最多的5个元素?,java,python-3.x,kotlin,Java,Python 3.x,Kotlin,我想写一个程序,例如显示文本中重复次数最多的5个单词。 保存在地图中的文字,其关键字为文字,其值为重复该文字的次数 这个程序显示重复次数最多的单词,但我不知道如何改进它以显示5个重复次数最多的单词(以及如何使用map代替list) 导入java.io.BufferedReader; 导入java.io.FileReader; 导入java.util.ArrayList; 公共类最重复的单词{ 公共静态void main(字符串[]args)引发异常{ 字符串行,word=“”; int coun

我想写一个程序,例如显示文本中重复次数最多的5个单词。 保存在地图中的文字,其关键字为文字,其值为重复该文字的次数

这个程序显示重复次数最多的单词,但我不知道如何改进它以显示5个重复次数最多的单词(以及如何使用map代替list)

导入java.io.BufferedReader;
导入java.io.FileReader;
导入java.util.ArrayList;
公共类最重复的单词{
公共静态void main(字符串[]args)引发异常{
字符串行,word=“”;
int count=0,maxCount=0;
ArrayList words=新的ArrayList();
//以读取模式打开文件
FileReader文件=新的FileReader(“data.txt”);
BufferedReader br=新的BufferedReader(文件);
//读每一行
而((line=br.readLine())!=null){
字符串[]=line.toLowerCase().split(([,.\\s]+))”;
//将上一步中生成的所有单词添加到单词中
对于(字符串s:String){
字。加上(s);
}    
}    
//确定文件中重复次数最多的单词
对于(inti=0;i最大计数){
最大计数=计数;
单词=单词。获取(i);
}    
}    
System.out.println(“最重复的单词:“+word”);
br.close();
}    
}   
按如下方式尝试:

        Map<String, Integer> words = new HashMap<>();

        try (BufferedReader br = new BufferedReader(new FileReader("data.txt "))) {
            String line;
            while ((line = br.readLine()) != null) {
                String string[] = line.toLowerCase().split("([,.\\s]+) ");
                //Adding all words generated in previous step into words
                for (String s : string) {
                    words.compute(s, (word, count) -> {
                        if (count == null)
                            return 1;
                        return count + 1;
                    });
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        final int TOP = 5;
        final List<Integer> topCounts = words.values().stream()
                .sorted(Comparator.reverseOrder())
                .limit(TOP)
                .collect(Collectors.toList());

        final String[] topWords = new String[TOP];
        words.forEach((word, count) -> {
            int indexOfWord = topCounts.indexOf(count);
            if (indexOfWord > -1) {
                topWords[indexOfWord] = word;
                topCounts.set(indexOfWord, -1);
            }
        });

        System.out.println("Top 5 most repeated words: " + Arrays.toString(topWords));
Map words=newhashmap();
try(BufferedReader br=new BufferedReader(new FileReader(“data.txt”)){
弦线;
而((line=br.readLine())!=null){
字符串[]=line.toLowerCase().split(([,.\\s]+))”;
//将上一步中生成的所有单词添加到单词中
for(字符串s:String){
单词。计算(单词,计数)->{
如果(计数=null)
返回1;
返回计数+1;
});
}
}
}捕获(IOE异常){
e、 printStackTrace();
}
最终int TOP=5;
最终列表topCounts=words.values().stream()
.sorted(Comparator.reverseOrder())
.限制(顶部)
.collect(Collectors.toList());
最终字符串[]topWords=新字符串[TOP];
单词。forEach((单词,计数)->{
int indexoford=topCounts.indexOf(count);
如果(indexoford>-1){
topWords[indexOfWord]=单词;
topCounts.set(indexoford,-1);
}
});
System.out.println(“重复次数最多的前5个单词:“+Arrays.toString(topWords));

简单的方法是首先计算每个单词的频率(计算它出现的次数),然后按频率对单词进行排序,然后显示结果的前五名。实际上,您不需要对所有这些文件进行排序,但这比只选择前5名要简单

让我们编写一些代码:

 class WordCounter {
     private Map<String, Integer> counts = new HashMap<>();

     public void count(String word) {
        int prev = counts.getOrDefault(word, 0);
        counts.put(word, prev+1);
     }

     public String[] top(int n) {
         String[] sorted = new String[counts.size()];
         int i=0;
         for (String s : counts.keySet()) sorted[i++] = s;
         Arrays.sort(sorted, (a,b) -> counts.get(b).compareTo(counts.get(a))); 
         return Arrays.copyOfRange(sorted, 0, n);
     }
 }
类字计数器{
私有映射计数=新HashMap();
公共无效计数(字符串字){
int prev=counts.getOrDefault(字,0);
计数。输入(字,上一个+1);
}
公共字符串[]顶部(整数n){
字符串[]排序=新字符串[counts.size()];
int i=0;
对于排序为[i++]=s的(字符串s:counts.keySet());
Arrays.sort(sorted,(a,b)->counts.get(b).compareTo(counts.get(a));
返回数组.copyOfRange(排序,0,n);
}
}

现在,我们在阅读每个单词后调用
count(word)
。这需要考虑频率。并在完成后调用
top(5)
,这将按计数(递减)对结果进行排序并返回前5名。

这是函数式风格可以导致代码更短的情况之一,希望更容易理解

一旦你有了
单词列表
,你就可以简单地使用:

words.groupingBy{ it }
     .eachCount()
     .toList()
     .sortedByDescending{ it.second }
     .take(5)
groupingBy()
从单词列表中创建一个键。(通常,您会提供一个键选择器函数,解释如何对项目进行分组,但在这种情况下,我们需要单词本身,因此
it
)因为我们只关心出现的次数,
eachCount()
获取计数(感谢Ilya和Tenfour04的支持。)

然后我们将映射转换成一个列表,准备进行排序。该列表由成对组成,单词作为第一个值,计数作为第二个值

因此,
sortedByDescending{it.second}
按计数排序。由于我们按降序排序,它首先给出最常用的单词

最后,
take(5)
从列表中获取前五个值,这将是五个最常见的单词(以及它们的计数)

例如,当我在几个简单的句子上运行时,它给出:
[(the,4),(was,3),(it,3),(a,2),(of,2)]

(如果您只需要单词,而不需要计数,那么可以使用
.map{it.first}
。此外,正如Tenfour04所建议的,有更好的方法从文本中提取单词;但一旦你开始考虑大小写、撇号、连字符、非ASCII字母等,这可能会变得相当复杂。这似乎是一个与获取最常用单词不同的问题。)

因为你标记了Kotlin,h
words.groupingBy{ it }
     .eachCount()
     .toList()
     .sortedByDescending{ it.second }
     .take(5)