Il modo più veloce per dividere una stringa delimitata in Java

8

Sto costruendo un comparatore che fornisce funzionalità di ordinamento a più colonne su una stringa delimitata. Attualmente sto usando il metodo split dalla classe String come scelta preferita per suddividere la stringa raw in token.

È questo il modo migliore per convertire la stringa raw in una matrice di stringhe? Ordinerò milioni di righe, quindi penso che l'approccio sia importante.

Sembra funzionare bene ed è molto facile, ma non è sicuro se c'è un modo più veloce in java.

Ecco come funziona l'ordinamento nel mio comparatore:

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

Dopo aver analizzato i vari approcci, credici o no, il metodo split è stato il più veloce utilizzando l'ultima versione di java. Puoi scaricare il mio comparatore completato qui: link

    
posta Constantin 20.12.2013 - 17:11
fonte

4 risposte

18

Ho scritto un test benchmark rapido e sporco per questo. Confronta 7 diversi metodi, alcuni dei quali richiedono una conoscenza specifica dei dati che vengono suddivisi.

Per la suddivisione di base per scopi generici, Guava Splitter è 3,5 volte più veloce di String # split () e consiglio di utilizzarlo. Stringtokenizer è leggermente più veloce di quello e dividersi con indexOf è due volte più veloce di nuovo.

Per il codice e maggiori informazioni vedi link

    
risposta data 20.12.2013 - 17:49
fonte
5

Come scrive @Tom, un approccio di tipo indexOf è più veloce di String.split() , poiché quest'ultimo si occupa di espressioni regolari e ha un sacco di overhead aggiuntivo per loro.

Tuttavia, una modifica dell'algoritmo potrebbe darti una super velocità. Supponendo che questo comparatore sarà usato per ordinare le tue ~ 100.000 stringhe, non scrivere Comparator<String> . Perché, nel corso del tuo ordinamento, la stessa stringa verrà probabilmente confrontata con più volte, quindi dividerla più volte, ecc ...

Dividi tutte le stringhe una volta in String [] se disponi di Comparator<String[]> per ordinare la stringa []. Quindi, alla fine, puoi combinarli tutti insieme.

In alternativa, potresti anche utilizzare una mappa per memorizzare nella cache String - > String [] o viceversa. per esempio. (abbozzato) Nota anche, stai scambiando memoria per velocità, spero tu abbia un sacco di 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
}
    
risposta data 21.12.2013 - 01:17
fonte
2

Secondo questo benchmark , StringTokenizer è più veloce per dividere le stringhe ma non restituisce un array che lo rende meno conveniente.

Se devi ordinare milioni di righe, ti consigliamo di utilizzare un RDBMS.

    
risposta data 20.12.2013 - 17:21
fonte
1

Questo è il metodo che utilizzo per analizzare file di grandi dimensioni (1GB +) delimitati da tabulazioni. Ha un sovraccarico molto inferiore a String.split() , ma è limitato a char come delimitatore. Se qualcuno ha un metodo più veloce, mi piacerebbe vederlo. Questo può anche essere fatto su CharSequence e CharSequence.subSequence , ma ciò richiede l'implementazione di CharSequence.indexOf(char) (fare riferimento al metodo del pacchetto String.indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) se interessati)

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;
}
    
risposta data 30.08.2017 - 17:31
fonte

Leggi altre domande sui tag