计算文件中任意数量字符的出现次数?

时间:2012-11-08 19:25:16

标签: java

我找到了几种方法来计算Java中文件中单个字符的出现次数。我的问题很简单:有没有办法同时计算文件中列表中任何字符的出现次数,或者我是否必须遍历每个字符?

为了澄清,我想要的东西相当于: 对于文件中的每个字符,如果列表“abcdefg”中的字符增加1。

背景: 我在计算文件中的谓词,我能想到的最好的方法是搜索<,>,==等的出现次数。

6 个答案:

答案 0 :(得分:4)

使用Map<Character, Integer>并浏览该文件。对于您测试的每个角色,看它是否在地图中。如果它没有添加值1,否则获取当前值,增加它并将其放回。同时测试TreeMapHashMap以查看最适合您的方法。现在您有一个完整的直方图,您可以轻松添加有趣的总和。

更新:看到您有兴趣查找序列。如果你想以良好的性能做到这一点,我会使用像lex这样的工具,但对于Java。一个快速谷歌引导我到这一个:http://www.cs.princeton.edu/~appel/modern/java/JLex/应该直接定义你感兴趣的令牌,然后计算它们应该非常简单。

更新2 :我忍不住要玩它。这是一个似乎使用上述工具的示例(免责声明:我没有使用该工具,所以这可能是完全错误的......):

import java.lang.System;
import java.util.Map;
import java.util.TreeMap;

class Sample {
  public static void main(String argv[]) throws java.io.IOException {
    Map<String,Integer> map = new TreeMap<>();

    Yylex yy = new Yylex(System.in);
    Yytoken t;
    while ((t = yy.yylex()) != null) {
      String text = t.mText;

      if (!text.isEmpty()) {
        Integer i = map.get(text);
        if (i == null) {
          map.put(text, 1);
        }
        else {
          map.put(text, map.get(text)+1);
        }
      }
    } 

    System.out.println(map);
  }
}

class Yytoken {
  public String mText;

  Yytoken(String text) {
   mText = text;
  }

  public String toString() {
    return "Token: " + mText;
  }
}

%%

OTHER=(.|[\r\n])

%% 

<YYINITIAL> "," { return (new Yytoken(yytext())); }
<YYINITIAL> ":" { return (new Yytoken(yytext())); }
<YYINITIAL> ";" { return (new Yytoken(yytext())); }
<YYINITIAL> "(" { return (new Yytoken(yytext())); }
<YYINITIAL> ")" { return (new Yytoken(yytext())); }
<YYINITIAL> "[" { return (new Yytoken(yytext())); }
<YYINITIAL> "]" { return (new Yytoken(yytext())); }
<YYINITIAL> "{" { return (new Yytoken(yytext())); }
<YYINITIAL> "}" { return (new Yytoken(yytext())); }
<YYINITIAL> "." { return (new Yytoken(yytext())); }
<YYINITIAL> "+" { return (new Yytoken(yytext())); }
<YYINITIAL> "-" { return (new Yytoken(yytext())); }
<YYINITIAL> "*" { return (new Yytoken(yytext())); }
<YYINITIAL> "/" { return (new Yytoken(yytext())); }
<YYINITIAL> "=" { return (new Yytoken(yytext())); }
<YYINITIAL> "<>" { return (new Yytoken(yytext())); }
<YYINITIAL> "<"  { return (new Yytoken(yytext())); }
<YYINITIAL> "<=" { return (new Yytoken(yytext())); }
<YYINITIAL> ">"  { return (new Yytoken(yytext())); }
<YYINITIAL> ">=" { return (new Yytoken(yytext())); }
<YYINITIAL> "&"  { return (new Yytoken(yytext())); }
<YYINITIAL> "|"  { return (new Yytoken(yytext())); }
<YYINITIAL> ":=" { return (new Yytoken(yytext())); }
<YYINITIAL> "#" { return (new Yytoken(yytext())); }
<YYINITIAL> {OTHER} { return (new Yytoken("")); }

答案 1 :(得分:2)

由于你想要计算超过1个字符的谓词(==,!=,&lt; - ,&gt; =),你需要一个PushBackReader,以便你可以查看下一个字符到确定实际谓词。

  • 发生频率

如果你能承受额外的依赖,那么我的建议是使用Multiset来计算频率。如果你不能那么你可以使用Map或基于数组的计数器(如果您的谓词集是有限的,我更喜欢这个,因为这简化了代码)。

  • 并行化?

使用上述方法更简单,因为您可以在单次通过中获得频率。如果您的文件很大或者必须计算许多文件的频率,那么您可以选择使用java Executors并行化它。

答案 2 :(得分:2)

贮藏

如果我理解正确,你不仅要找到单个字符的出现次数,还要找到短字符序列(即字符串),例如==。在这种情况下,Map<Character, Integer>不足,您需要Map<String, Integer>来存储每个字符串的计数。

您也可以使用GuavaMultiset,它基本上是一个很好的接口,可以知道它包含重复(相同)元素的次数。

我相信你想要计算的谓词/运算符/任何短字符串的数量,你可以定义一个数组/列表,它将存储你感兴趣的所有谓词,例如: / p>

List<String> operators = Arrays.asList("==", "<=", ">=", "<", ">");

然后你会把所有这些操作符“倒”作为地图的键并将它们的值初始化为零:

Map<String, Integer> counts = new HashMap<>();
for (String operator : operators)
    counts.put(operator, 0);

解析

对于解析,您可以使用Scanner逐行轻松读取文件。对于每一行,您可以使用这样的方法来计算它包含给定子字符串的次数:

static int occurrences(String source, String subString) {
    int count = 0;
    int index = source.indexOf(subString);

    while (index != -1) {
        count++;
        index = source.indexOf(subString, index + 1);
    }
    return count;
}

然后以类似的方式使用此方法:

Scanner scanner = new Scanner(new File("input.txt"));
while (scanner.hasNextLine()) {
    String line = scanner.nextLine();
    for (String operator : operators) {
        int oldOccurences = counts.get(operator);
        counts.put(operator, oldOccurences + occurrences(line, operator));
    }
}

答案 3 :(得分:1)

我相信java列表界面有一个Contains()方法,所以你可以做类似

的事情
if(someList.Contains('<'))
{
    x++
}

IT实际上并没有立即检查它们,但无论如何这些东西都是隐藏的

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/List.html

答案 4 :(得分:1)

要“count the occurrence of any of the characters in a list in a file simultaneously”:

  • 您可以使用HashTable,其中键是字符,值是您看到该字符的次数。
  • 每次阅读角色时,请检查它是否在HashTable中:
    • 如果是,请将其值增加1
    • 如果没有,请将键,值对添加到HashTable,其值初始化为1

如果您关心的字符集很小(例如示例中的"abcdefg""<, >, =="),则switch语句就足以代替使用HashTable来解决问题

答案 5 :(得分:0)

一个简单的方法是使用数组:

final int[] occurs = new int[65536];
for (char c : file) occurs[c]++;

如果你知道你不会遇到过于异国情调的字符,你可以减小数组的大小。