区切られた文字列で複数列のソート機能を提供するコンパレータを構築しています。私は現在、Stringクラスのsplitメソッドを、生のStringをトークンに分割するための推奨選択肢として使用しています。
これは、生の文字列を文字列配列に変換するための最良の方法ですか?数百万行を並べ替えるので、アプローチが重要だと思います。
正常に動作するようで非常に簡単ですが、Javaでより高速な方法があるかどうかは不明です。
これが私のコンパレータでのソートの仕組みです:
public int compare(String a, String b) {
String[] aValues = a.split(_delimiter, _columnComparators.length);
String[] bValues = b.split(_delimiter, _columnComparators.length);
int result = 0;
for( int index : _sortColumnIndices ) {
result = _columnComparators[index].compare(aValues[index], bValues[index]);
if(result != 0){
break;
}
}
return result;
}
さまざまなアプローチのベンチマークを行った後、信じられないかもしれませんが、splitメソッドはJavaの最新バージョンを使用した場合に最も迅速でした。ここに私の完成したコンパレータをダウンロードできます: https://sourceforge.net/projects/multicolumnrowcomparator/
私はこのための迅速で汚れたベンチマークテストを作成しました。 7つの異なる方法を比較します。そのうちのいくつかは、分割されるデータの特定の知識を必要とします。
基本的な汎用分割では、Guava SplitterはString#split()より3.5倍高速であり、それを使用することをお勧めします。 Stringtokenizerはそれよりもわずかに高速で、indexOfを使用した分割は、2倍高速です。
コードと詳細については http://demeranville.com/battle-of-the-tokenizers-delimited-text-parser-performance/ を参照してください
@Tomが書いているように、indexOfタイプのアプローチはString.split()
よりも高速です。後者は正規表現を処理し、それらのオーバーヘッドが多くなるためです。
ただし、1つのアルゴリズムの変更により、速度が大幅に向上する場合があります。このコンパレータが〜100,000文字列のソートに使用されると想定している場合は、Comparator<String>
。なぜなら、ソートの過程で、同じ文字列が比較される可能性が高いためmultiple回なので、分割しますmultiple回など.
すべての文字列onceをString [] sに分割し、Comparator<String[]>
String []をソートします。その後、最後にそれらをすべて組み合わせることができます。
または、マップを使用してString-> String []をキャッシュすることも、その逆も可能です。例えば(スケッチ)また、速度とメモリを交換していることに注意してください。たくさんのRAMがあることを願っています
HashMap<String, String[]> cache = new HashMap();
int compare(String s1, String s2) {
String[] cached1 = cache.get(s1);
if (cached1 == null) {
cached1 = mySuperSplitter(s1):
cache.put(s1, cached1);
}
String[] cached2 = cache.get(s2);
if (cached2 == null) {
cached2 = mySuperSplitter(s2):
cache.put(s2, cached2);
}
return compareAsArrays(cached1, cached2); // real comparison done here
}
このベンチマーク によると、StringTokenizerは文字列を分割する方が高速ですが、配列を返さないため、あまり便利ではありません。
数百万行をソートする必要がある場合は、RDBMSを使用することをお勧めします。
これは、大きな(1GB +)タブ区切りファイルの解析に使用する方法です。オーバーヘッドはString.split()
よりはるかに少なくなりますが、区切り文字としてchar
に制限されます。誰かがより速い方法を持っているなら、私はそれを見たいです。これはCharSequence
および_CharSequence.subSequence
_でも実行できますが、CharSequence.indexOf(char)
の実装が必要です(パッケージメソッドを参照 String.indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)
興味がある場合)。
_public static String[] split(final String line, final char delimiter)
{
CharSequence[] temp = new CharSequence[(line.length() / 2) + 1];
int wordCount = 0;
int i = 0;
int j = line.indexOf(delimiter, 0); // first substring
while (j >= 0)
{
temp[wordCount++] = line.substring(i, j);
i = j + 1;
j = line.indexOf(delimiter, i); // rest of substrings
}
temp[wordCount++] = line.substring(i); // last substring
String[] result = new String[wordCount];
System.arraycopy(temp, 0, result, 0, wordCount);
return result;
}
_