【问题标题】:Count frequency of a string individually from query从查询中单独计算字符串的频率
【发布时间】:2020-08-16 14:57:56
【问题描述】:

我想从名为 a.java 的文件中搜索查询。如果我的查询是字符串名称,我想从文本文件的查询中单独获取字符串的频率。首先,我必须计算字符串的频率,然后单独命名,然后将频率都添加。如何在java平台上实现这个程序?

public class Tf2 {
Integer k;
int totalword = 0;
int totalfile, containwordfile = 0;
Map<String, Integer> documentToCount = new HashMap<>();
File file = new File("H:/java");
File[] files = file.listFiles();
public void Count(String word) {
   File[] files = file.listFiles();
    Integer count = 0;
    for (File f : files) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(f));
            count = documentToCount.get(word);

            documentToCount.clear();

            String line;
            while ((line = br.readLine()) != null) {
                String term[] = line.trim().replaceAll("[^a-zA-Z0-9 ]", " ").toLowerCase().split(" ");


                for (String terms : term) {
                    totalword++;
                    if (count == null) {
                        count = 0;
                    }
                    if (documentToCount.containsKey(word)) {

                        count = documentToCount.get(word);
                        documentToCount.put(terms, count + 1);
                    } else {
                        documentToCount.put(terms, 1);

                    }

                }

            }
          k = documentToCount.get(word);

            if (documentToCount.get(word) != null) {
                containwordfile++;
       
               System.out.println("" + k);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
} public static void main(String[] args) throws IOException {Tf2  ob = new Tf2();String query="String name";ob.Count(query);
}}

我用 hashmap 试过这个。但它不能单独统计查询的频率。

【问题讨论】:

  • 你能提供一个示例文本和预期结果吗?
  • @aeberhart 好的,我会向你澄清。如果我有一个包含一行的文件,请点击此处维基百科是免费的在线百科全书,由世界各地的志愿者创建和编辑.我想搜索一个查询edited Wikipedia志愿者。然后我的程序首先计算从文本文件中编辑的频率,然后计算维基百科频率,然后是志愿者频率,最后总结所有频率。可以用 hashmap 解决吗?
  • 您希望对同一文本进行多少次查询?如果会有多个查询,那么您可以相应地进行优化。如果有一个查询,那么最好的选择是将查询的单词放入一个集合中,然后逐个遍历实际单词。因此复杂度将是 O(n + k),其中 n 是文本中的单词数。而 k 是查询中的单词数

标签: java algorithm file hashmap tf-idf


【解决方案1】:

这是一个使用 Collections.frequency 获取文件中字符串计数的示例:

public void Count(String word) {
    File f = new File("/your/path/text.txt");
    BufferedReader br = null;
    List<String> list = new ArrayList<String>();
    try {
        if (f.exists() && f.isFile()) {
            br = new BufferedReader(new FileReader(f));
            String line;
            while ((line = br.readLine()) != null) {
                String[] arr = line.split(" ");
                for (String str : arr) {
                    list.add(str);
                }

            }
            System.out.println("Frequency = " + Collections.frequency(list, word));
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}

这是另一个使用 Java Streams API 的示例,也适用于目录内的多文件搜索:

    public class Test {

    public static void main(String[] args) {
        File file = new File("C:/path/to/your/files/");
        String targetWord = "stringtofind";
        long numOccurances = 0;

        if(file.isFile() && file.getName().endsWith(".txt")){

            numOccurances = getLineStreamFromFile(file)
                    .flatMap(str -> Arrays.stream(str.split("\\s")))
                    .filter(str -> str.equals(targetWord))
                    .count();

        } else if(file.isDirectory()) {

            numOccurances = Arrays.stream(file.listFiles(pathname -> pathname.toString().endsWith(".txt")))
                    .flatMap(Test::getLineStreamFromFile)
                    .flatMap(str -> Arrays.stream(str.split("\\s")))
                    .filter(str -> str.equals(targetWord))
                    .count();
        }

        System.out.println(numOccurances);
    }

    public static Stream<String> getLineStreamFromFile(File file){
        try {
            return Files.lines(file.toPath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Stream.empty();
    }
  }

此外,您可以将输入字符串分解为单个单词并循环以获取每个单词的出现次数。

【讨论】:

  • 这里,我的问题是我是否有一个文件包含一行“维基百科是免费的在线百科全书,由世界各地的志愿者创建和编辑”。我想搜索一个查询“编辑的维基百科志愿者".然后我的程序先统计从文本文件中编辑的频率,然后统计维基百科的频率,然后是志愿者的频率,最后将所有的频率相加。可以用 hashmap 解决吗?
  • @SanzidaSultana 您可以使用 Collections.frequency 分别找到已编辑、维基百科、志愿者的频率,并将频率相加.....您是否有任何具体原因想要使用 Hashmap 实现相同的目标?
  • 感谢您的反馈。如果我的查询是包含 5 个单词的行,我应该调用 collections.frequency 5 次吗? public void Count(String word) 在此处的参数中,我必须将查询作为 public void count(edited Wikipedia志愿者 free oline) 之类的行发送,但要从单独查询。hasmap没有具体原因。只是为了练习
【解决方案2】:

如果我的文件包含“维基百科是免费的在线 百科全书,由世界各地的志愿者创建和编辑”。I 想搜索一个查询“编辑过的维基百科志愿者”。然后我的程序 首先计算从文本文件中编辑的频率,然后计算 维基百科频率,然后是志愿者频率,最后相加 提高所有频率。可以用hashmap解决吗?

你可以这样做:

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        // The given string
        String str = "Wikipedia is a free online encyclopedia, created and edited by volunteers around the world.";

        // The query string
        String query = "edited Wikipedia volunteers";

        // Split the given string and the query string on space
        String[] strArr = str.split("\\s+");
        String[] queryArr = query.split("\\s+");

        // Map to hold the frequency of each word of query in the string
        Map<String, Integer> map = new HashMap<>();

        for (String q : queryArr) {
            for (String s : strArr) {
                if (q.equals(s)) {
                    map.put(q, map.getOrDefault(q, 0) + 1);
                }
            }
        }

        // Display the map
        System.out.println(map);

        // Get the sum of all frequencies
        int sumFrequencies = map.values().stream().mapToInt(Integer::intValue).sum();

        System.out.println("Sum of frequencies: " + sumFrequencies);
    }
}

输出:

{edited=1, Wikipedia=1, volunteers=1}
Sum of frequencies: 3

查看the documentation of Map#getOrDefault 了解更多信息。

更新

在原始答案中,我使用 Java Stream API 来获取值的总和。下面给出了另一种方法:

// Get the sum of all frequencies
int sumFrequencies = 0;
for (int value : map.values()) {
    sumFrequencies += value;
}

你的另一个问题是:

如果我在一个文件夹中有多个文件,那么我怎么知道有多少 此查询操作系统出现在哪个文件中的次数

您可以创建一个Map&lt;String, Map&lt;String, Integer&gt;&gt;,其中的键是文件名,值(即Map&lt;String, Integer&gt;)是文件的频率图。我已经在上面展示了创建这个频率图的算法。您所要做的就是遍历文件列表并填充此地图 (Map&lt;String, Map&lt;String, Integer&gt;&gt;)。

【讨论】:

  • 如果我的查询是=“编辑维基百科志愿者”,我可以计算编辑和编辑的频率吗?我听到一个关于蒸汽的话题。但起初对我来说似乎很困难。还有其他解决方案吗?请不要介意我的问题,因为我在这里很基础
  • @SanzidaSultana - 我刚刚发布了您最后评论的更新。我希望更新回答您在评论中的其他问题。对于进一步的问题,我建议您发布一个新问题。
  • int sumFrequencies = map.values().stream().mapToInt(Integer::intValue).sum(); 这行代码用于总结出现次数.但我无法理解那些调用方法。另一个问题是,如果我在一个文件夹中有多个文件,那么我怎么知道这个查询在哪个文件中发生了多少次,并将其存储在一个集合中以供进一步使用。我可以使用映射吗?如果我问任何愚蠢的问题,请不要介意
  • 这正是我想要的。
【解决方案3】:

你把事情搞得太复杂了。如果您只需要计算出现次数,则不需要哈希图或类似的东西。您需要做的就是遍历文档中的所有文本并计算您找到搜索字符串的次数。

基本上,您的工作流程是:

  1. 将计数器实例化为 0
  2. 阅读文字
  3. 遍历文本,寻找搜索字符串
  4. 找到搜索字符串后,递增计数器
  5. 完成对文本的迭代后,打印计数器的结果

如果您的文本很长,您可以逐行执行此操作或以其他方式批量读取。

这是一个简单的例子。假设我有一个文件,我正在寻找“狗”这个词。

// 1. instantiate counter to 0
int count = 0;

// 2. read text
Path path = ...; // path to my input file
String text = Files.readString(path, StandardCharsets.US_ASCII);

// 3-4. find instances of the string in the text
String searchString = "dog";

int lastIndex = 0;
while (lastIndex != -1) {
  lastIndex = text.indexOf(searchString, lastIndex); // will resolve -1 if the searchString is not found
  if (lastIndex != -1) {
    count++; // increment counter
    lastIndex += searchString.length(); // increment index by length of search term
  }
}

// 5. print result of counter
System.out.println("Found " + count + " instances of " + searchString);

在您的具体示例中,您将阅读 a.java 类的内容,然后找到“String”实例的数量,然后是“name”实例的数量。您可以在闲暇时将它们汇总在一起。因此,您需要对要搜索的每个单词重复第 3 步和第 4 步,然后在最后总结所有计数。

当然,最简单的方法是将步骤 3 和 4 包装在一个返回计数的方法中。

int countOccurrences(String searchString, String text) {
  int count = 0;
  int lastIndex = 0;
  while (lastIndex != -1) {
    lastIndex = text.indexOf(searchString, lastIndex);
    if (lastIndex != -1) {
      count++;
      lastIndex += searchString.length();
    }
  }
  return count;
}

// Call:
int nameCount = countOccurrences("name", text);
int stringCount = countOccurrences("String", text);

System.out.println("Counted " + nameCount + " instances of 'name' and " + stringCount + " instances of 'String', for a total of " + (nameCount + stringCount));

(是否对text 进行toLowerCase() 取决于您是否需要区分大小写的匹配项。)

当然,如果您只想要“姓名”而不想要“姓氏”,那么您将开始需要考虑诸如单词边界之类的事情(正则表达式字符类 \b 在这里很有用。)对于解析打印文本,您' 将需要考虑用连字符跨行结束的单词。但听起来您的用例只是简单地计算以空格分隔的字符串中恰好提供给您的单个单词的实例。

如果您实际上只想将String name 的实例作为这样的单个短语,只需使用第一个工作流程。


其他有用的问答:

【讨论】:

    【解决方案4】:

    您可以使用以单词为键,计数为值的映射:

      public static void main(String[] args) {
        String corpus =
            "Wikipedia is a free online encyclopedia, created and edited by volunteers around the world";
        String query = "edited Wikipedia volunteers";
    
        Map<String, Integer> word2count = new HashMap<>();
        for (String word : corpus.split(" ")) {
          if (!word2count.containsKey(word))
            word2count.put(word, 0);
          word2count.put(word, word2count.get(word) + 1);
        }
    
        for (String q : query.split(" "))
          System.out.println(q + ": " + word2count.get(q));
      }
    

    【讨论】:

    • 感谢您的反馈。我还有一个问题,如果我在一个文件夹中有多个文件,那么我怎么知道这个查询在哪个文件中发生了多少次并将其存储在一个集合中进一步使用。我可以使用映射吗?请不要介意我问任何愚蠢的问题-
    • 您可以使用 Map> file2count,其中第一个键是文件名。所以 file2count("f.txt").get("word")) 会给你文件“f.txt”中“word”的计数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-18
    • 2017-04-19
    • 1970-01-01
    • 2023-03-25
    • 2011-10-06
    • 2019-08-07
    相关资源
    最近更新 更多