it-swarm.com.de

Der schnellste Weg, einen durch Trennzeichen getrennten String in Java

Ich erstelle einen Komparator, der mehrspaltige Sortierfunktionen für eine begrenzte Zeichenfolge bietet. Ich verwende derzeit die Split-Methode aus der String-Klasse als meine bevorzugte Wahl für die Aufteilung des rohen Strings in Token.

Ist dies die leistungsstärkste Methode, um den rohen String in ein String-Array zu konvertieren? Ich werde Millionen von Zeilen sortieren, also denke ich, dass der Ansatz wichtig ist.

Es scheint gut zu laufen und ist sehr einfach, aber unsicher, ob es in Java einen schnelleren Weg gibt.

So funktioniert die Sortierung in meinem Komparator:

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;
}

Ob Sie es glauben oder nicht, nach dem Benchmarking der verschiedenen Ansätze war die Split-Methode mit der neuesten Java-Version die schnellste. Sie können meinen fertigen Komparator hier herunterladen: https://sourceforge.net/projects/multicolumnrowcomparator/

10
Constantin

Ich habe dafür einen schnellen und schmutzigen Benchmark-Test geschrieben. Es werden 7 verschiedene Methoden verglichen, von denen einige spezifische Kenntnisse der zu teilenden Daten erfordern.

Für die allgemeine Aufteilung für allgemeine Zwecke ist Guava Splitter 3,5-mal schneller als String # split (), und ich würde empfehlen, dies zu verwenden. Stringtokenizer ist etwas schneller und das Aufteilen mit indexOf ist doppelt so schnell wie wieder.

Für den Code und weitere Informationen siehe http://demeranville.com/battle-of-the-tokenizers-delimited-text-parser-performance/

19
tom

Wie @Tom schreibt, ist ein Ansatz vom Typ indexOf schneller als String.split(), da letzterer reguläre Ausdrücke behandelt und viel zusätzlichen Aufwand für sie hat.

Eine Änderung des Algorithmus kann jedoch zu einer erheblichen Beschleunigung führen. Angenommen, dieser Komparator wird zum Sortieren Ihrer ~ 100.000 Zeichenfolgen verwendet, schreiben Sie nicht das Comparator<String>. Da im Verlauf Ihrer Sortierung wahrscheinlich derselbe String mehrfach mal verglichen wird, teilen Sie ihn also mehrfach mal usw. auf.

Teilen Sie alle Strings einmal in String [] s und haben Sie ein Comparator<String[]> sortiere den String []. Am Ende können Sie sie dann alle miteinander kombinieren.

Alternativ können Sie auch eine Map verwenden, um den String -> String [] zwischenzuspeichern oder umgekehrt. z.B. (skizzenhaft) Beachten Sie auch, dass Sie Speicher gegen Geschwindigkeit eintauschen und hoffen, dass Sie viel RAM haben

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
}
5
user949300

Laut dieser Benchmark ist StringTokenizer schneller zum Teilen von Strings, gibt jedoch kein Array zurück, was es weniger bequem macht.

Wenn Sie Millionen von Zeilen sortieren müssen, würde ich die Verwendung eines RDBMS empfehlen.

2

Dies ist die Methode, die ich zum Parsen großer (1 GB +) tabulatorgetrennter Dateien verwende. Es hat weitaus weniger Overhead als String.split(), ist jedoch auf char als Trennzeichen beschränkt. Wenn jemand eine schnellere Methode hat, würde ich sie gerne sehen. Dies kann auch über CharSequence und CharSequence.subSequence Durchgeführt werden, erfordert jedoch die Implementierung von CharSequence.indexOf(char) (siehe Paketmethode String.indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) = bei Interesse).

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;
}
1
vallismortis