【问题标题】:How to count the number of occurrences of words in a text如何计算文本中单词的出现次数
【发布时间】:2012-12-08 09:28:45
【问题描述】:

我正在编写一个程序来查找文本中最常用的 10 个单词,但我遇到了困难,不知道下一步该怎么做。有人可以帮帮我吗?

我只走了这么远:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;

public class Lab4 {
    public static void main(String[] args) throws FileNotFoundException {
        Scanner file = new Scanner(new File("text.txt")).useDelimiter("[^a-zA-Z]+");
        List<String> words = new ArrayList<String>();
        while (file.hasNext()){
            String tx = file.next();
            // String x = file.next().toLowerCase();
            words.add(tx);
        }
        Collections.sort(words);
        // System.out.println(words);
    }
}

【问题讨论】:

  • 一个 List 的单词是不够的,你还需要一个 count 的每个单词出现。你会为这样的任务使用什么数据结构? (显然,这是作业,这就是我提出这个问题的原因)
  • 我认为您阅读文件的方式存在错误。 file.next() 最终会为空,所以你应该检查一下。

标签: java


【解决方案1】:

您可以使用 Guava Multiset,这是一个字数统计示例:http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained

下面是如何在 Multiset 中找到计数最高的单词:Simplest way to iterate through a Multiset in the order of element frequency?

更新我在 2012 年写了这个答案。从那时起我们有了 Java 8,现在可以在没有外部库的情况下在几行中找到 10 个最常用的单词:

List<String> words = ...

// map the words to their count
Map<String, Integer> frequencyMap = words.stream()
         .collect(toMap(
                s -> s, // key is the word
                s -> 1, // value is 1
                Integer::sum)); // merge function counts the identical words

// find the top 10
List<String> top10 = words.stream()
        .sorted(comparing(frequencyMap::get).reversed()) // sort by descending frequency
        .distinct() // take only unique values
        .limit(10)   // take only the first 10
        .collect(toList()); // put it in a returned list

System.out.println("top10 = " + top10);

静态导入是:

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

【讨论】:

  • 投反对票,因为仅将库用于如此简单的任务实在是太过分了。
  • 谁说 OP 应该“只”使用 Guava 来完成这项任务?对于优秀的 Java 程序员来说,Guava 就像标准的集合。你只需要知道它。 Multimap 有望被添加到 Java 8 中。
  • 对不起,先生,我不是 Java 开发人员(实际上讨厌它),所以我不知道 Guava 是这样的东西。关键是,OP 的措辞和具体问题让我相信他可能刚刚开始,在那个阶段引入 3rd 方依赖项是一个坏主意。
  • 如果答案“没有用”,您应该投反对票,如果您认为答案“太高级”,则不应投反对票。 Stackoverflow 也是供以后参考的,不知道以后谁会觉得这个解决方案优雅实用……
  • 虽然您的评论完全有效,让我稍微改变了看法,但我仍然不得不争辩说我的反对意见是有效的,因为其他答案更适合手头的问题。我投了反对票,因为这个答案即使是有效的,也不应该被 OP 视为最佳方法,至少再次,因为我认为他的技能水平是。
【解决方案2】:

创建地图以跟踪此类事件:

   Scanner file = new Scanner(new File("text.txt")).useDelimiter("[^a-zA-Z]+");
   HashMap<String, Integer> map = new HashMap<>();

   while (file.hasNext()){
        String word = file.next().toLowerCase();
        if (map.containsKey(word)) {
            map.put(word, map.get(word) + 1);
        } else {
            map.put(word, 0);
        }
    }

    ArrayList<Map.Entry<String, Integer>> entries = new ArrayList<>(map.entrySet());
    Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {

        @Override
        public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
            return a.getValue().compareTo(b.getValue());
        }
    });

    for(int i = 0; i < 10; i++){
        System.out.println(entries.get(entries.size() - i - 1).getKey());
    }

【讨论】:

    【解决方案3】:

    这是一个比来自 lbalazscs 的版本更短的版本,它也使用 Java 8 的流 API;

    Arrays.stream(new String(Files.readAllBytes(PATH_TO_FILE), StandardCharsets.UTF_8).split("\\W+"))
                .collect(Collectors.groupingBy(Function.<String>identity(), HashMap::new, counting()))
                .entrySet()
                .stream()
                .sorted(((o1, o2) -> o2.getValue().compareTo(o1.getValue())))
                .limit(10)
                .forEach(System.out::println);
    

    这将一次性完成所有操作:加载文件,按非单词字符拆分,按单词对所有内容进行分组并为每个组分配单词计数,然后为前十个单词打印带有计数的单词。

    有关非常相似的设置的一些深入讨论,另请参阅:https://stackoverflow.com/a/33946927/327301

    【讨论】:

    • 为什么不使用现有的比较器.sorted(Entry.compareByValue().reversed())? (可能带有类型参数)。
    【解决方案4】:
    package src;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Scanner;
    import java.util.Map.Entry;
    
    public class ScannerTest
    {
        public static void main(String[] args) throws FileNotFoundException
            {
            Scanner scanner = new Scanner(new File("G:/Script_nt.txt")).useDelimiter("[^a-zA-Z]+");
            Map<String, Integer> map = new HashMap<String, Integer>();
            while (scanner.hasNext())
                {
                String word = scanner.next();
                if (map.containsKey(word))
                    {
                    map.put(word, map.get(word)+1);
                    }
                else
                    {
                    map.put(word, 1);
                    }
                }
    
            List<Map.Entry<String, Integer>> entries = new ArrayList<Entry<String,Integer>>( map.entrySet());
    
            Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
    
                @Override
                public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
                    return a.getValue().compareTo(b.getValue());
                }
            });
    
            for(int i = 0; i < map.size(); i++){
                System.out.println(entries.get(entries.size() - i - 1).getKey()+" "+entries.get(entries.size() - i - 1).getValue());
            }
            }
    }
    

    【讨论】:

      【解决方案5】:

      从文件或命令行以字符串的形式在输入中创建并将其传递给下面的方法,它将返回一个映射,其中包含作为键的单词和作为它们在该句子或段落中出现或计数的值。

      public Map<String,Integer> getWordsWithCount(String sentances)
      {
          Map<String,Integer> wordsWithCount = new HashMap<String, Integer>();
      
          String[] words = sentances.split(" ");
          for (String word : words)
          {
              if(wordsWithCount.containsKey(word))
              {
                  wordsWithCount.put(word, wordsWithCount.get(word)+1);
              }
              else
              {
                  wordsWithCount.put(word, 1);
              }
      
          }
      
          return wordsWithCount;
      
      }
      

      【讨论】:

        猜你喜欢
        • 2014-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-04
        • 1970-01-01
        • 2018-08-25
        • 1970-01-01
        相关资源
        最近更新 更多