我找到了几种方法来计算 Java 文件中单个字符的出现次数。我的问题很简单:有没有办法同时计算文件中列表中任何字符的出现,还是我必须遍历每个字符?
为了澄清,我想要的东西相当于:对于文件中的每个字符,如果列表“abcdefg”中的字符增加 1。
背景:我正在计算文件中的谓词,我能想到的最好方法是搜索 <、>、== 等的出现。
我找到了几种方法来计算 Java 文件中单个字符的出现次数。我的问题很简单:有没有办法同时计算文件中列表中任何字符的出现,还是我必须遍历每个字符?
为了澄清,我想要的东西相当于:对于文件中的每个字符,如果列表“abcdefg”中的字符增加 1。
背景:我正在计算文件中的谓词,我能想到的最好方法是搜索 <、>、== 等的出现。
使用 aMap<Character, Integer>
并浏览文件。对于您测试的每个角色,看看它是否在地图中。如果不是加上值1,否则获取当前值,将其递增并放回。测试两者TreeMap
,HashMap
看看哪个最适合你。现在您有了一个完整的直方图,您可以轻松添加有趣的总和。
更新:看到您对查找序列感兴趣。如果你想以良好的性能做到这一点,我会使用像 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 个字符(==、!=、<-、>=)的谓词,因此您需要一个PushBackReader以便您可以查看下一个字符以确定实际谓词。
如果你能负担得起额外的依赖,那么我的建议是使用Multiset来计算频率。如果你不能,那么你可以使用基于 Map 或数组的计数器(如果你的谓词集是有限的,我更喜欢这个,因为这简化了代码)。
使用上述方法更简单,因为您可以通过 1 次单程获得频率。如果您的文件很大或者必须计算许多文件的频率,那么您可以选择使用 java Executors 并行化它。
如果我理解正确,您不仅希望找到单个字符的出现次数,还希望找到短字符序列(即字符串)的出现次数,例如==
. 在这种情况下, aMap<Character, Integer>
是不够的,您需要 aMap<String, Integer>
为每个字符串存储一个计数。
您也可以使用Guava的Multiset,这对于一个知道它包含多少次重复(相同)元素的集合来说基本上是一个很好的接口。
我相信定义了您想要计算的谓词/运算符/任何短字符串的数量,您可以定义一个数组/一个列表来存储您感兴趣的所有谓词,例如:
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));
}
}
我相信java列表接口有一个Contains()
方法,所以你可以做类似的事情
if(someList.Contains('<'))
{
x++
}
IT 实际上并没有一次检查所有这些,但无论如何这些东西对你是隐藏的
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/List.html
对“ count the occurrence of any of the characters in a list in a file simultaneously
”:
如果您关心的字符集很小(例如您的示例中的"abcdefg"
or "<, >, =="
),则 switch 语句就足够了,而不是使用 HashTable 来解决问题
一个简单的方法是使用数组:
final int[] occurs = new int[65536];
for (char c : file) occurs[c]++;
如果您知道不会遇到太奇特的字符,则可以减小数组的大小。