Java でファイル内の単一文字の出現を数える方法をいくつか見つけました。私の質問は次のとおりです。ファイル内のリスト内の文字の出現を同時にカウントする方法はありますか、それとも各文字をループする必要がありますか?
明確にするために、私は次のようなものを望んでいます。
背景: ファイル内の述語を数えていますが、考えられる最善の方法は、<、>、== などの出現箇所を検索することでした。
Java でファイル内の単一文字の出現を数える方法をいくつか見つけました。私の質問は次のとおりです。ファイル内のリスト内の文字の出現を同時にカウントする方法はありますか、それとも各文字をループする必要がありますか?
明確にするために、私は次のようなものを望んでいます。
背景: ファイル内の述語を数えていますが、考えられる最善の方法は、<、>、== などの出現箇所を検索することでした。
a を使用しMap<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が必要になります。
追加の依存関係を持つ余裕がある場合は、頻度をカウントすることを目的としたマルチセットを使用することをお勧めします。できない場合は、マップまたは配列ベースのカウンターを使用できます(述語セットが有限の場合は、コードが単純化されるため、これをお勧めします)。
上記のアプローチを使用すると、1回のパスで周波数を取得できるため、より簡単になります。ファイルが巨大であるか、多数のファイルの頻度をカウントする必要がある場合は、Javaエグゼキューターを使用してこれを並列化することを選択できます。
私の理解が正しければ、単一の文字だけでなく、==
. その場合、aでは不十分です。文字列ごとにカウントを格納するには、aMap<Character, Integer>
が必要です。Map<String, Integer>
代わりにGuavaのMultisetを使用することもできます。これは基本的に、重複した (同じ) 要素が何回含まれているかを知るコレクションの優れたインターフェイスです。
述語/演算子/数えたい短い文字列の数が定義されていると思います。次のように、興味のあるすべての述語を格納する配列/リストを定義できます。
List<String> operators = Arrays.asList("==", "<=", ">=", "<", ">");
次に、これらすべての演算子をキーとしてマップに「注ぎ」、それらの値をゼロに初期化します。
Map<String, Integer> counts = new HashMap<>();
for (String operator : operators)
counts.put(operator, 0);
解析に関しては、 Scannerを使用してファイルを 1 行ずつ簡単に読み取ることができます。各行について、次のようなメソッドを使用して、指定された部分文字列が含まれる回数をカウントできます。
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など"<, >, =="
)、HashTable を使用して問題を解決する代わりに、switch ステートメントで十分です。
それを行う簡単な方法は、配列を使用することです。
final int[] occurs = new int[65536];
for (char c : file) occurs[c]++;
特殊な文字に遭遇しないことがわかっている場合は、配列のサイズを減らすことができます。