2010-05-21 5 views
5

Voglio determinare se una stringa è il nome di un mese e voglio farlo in tempi relativamente brevi. La funzione che è attualmente bloccato nel mio cervello è qualcosa di simile:Esiste un metodo più veloce per associare una stringa arbitraria al nome del mese in Java

boolean isaMonth(String str) { 
    String[] months = DateFormatSymbols.getInstance().getMonths(); 
    String[] shortMonths = DateFormatSymbols.getInstance().getShortMonths(); 
    int i; 

    for(i = 0; i<months.length(); ++i;) { 
     if(months[i].equals(str)) return true; 
     if(shortMonths[i].equals(str) return true; 
    } 
    return false; 
} 

Tuttavia, sarà procedante molto testo, passò una corda alla volta a questa funzione, e la maggior parte del tempo mi sarà sempre la il caso peggiore di passare attraverso l'intero ciclo e restituire false.

Ho visto un'altra domanda che parlava di un Regex per abbinare un nome di mese e un anno che potrebbe essere adattato per questa situazione. Il Regex sarebbe più veloce? C'è qualche altra soluzione che potrebbe essere più veloce?

+0

per i principianti, è possibile spostare/rendere mesi, brevi variabili di membri statici di ShortMonth (allocare solo una volta) .. –

+0

un regexp dovrebbe essere veloce. Una macchina a stati personalizzati più veloce. – SyntaxT3rr0r

risposta

3

Perché non memorizzare i nomi dei mesi in un HashSet? Questo ti darà una ricerca costante di tempo invece della ricerca lineare del tempo che stai ricevendo dal tuo ciclo.

import java.util.HashSet; 
import java.util.Collections; 
import java.text.DateFormatSymbols; 

class Test { 
    public static void main(String[] args) { 

    HashSet<String> months = new HashSet<String>(24); 

    Collections.addAll(months, DateFormatSymbols.getInstance().getMonths()); 
    Collections.addAll(months, DateFormatSymbols.getInstance().getShortMonths()); 

    System.out.println(months.contains(args[0])); 

    } 
} 
+2

Cosa dire di 'Collections.addAll (months, DateFormatSymbols.getInstance(). GetMonths())'? – msandiford

+0

Buona chiamata, ha cambiato il codice – dbyrne

+0

Questa risposta mi ha fatto andare nella giusta direzione. Mi piace anche un po 'di ciò che Kevin Day dice un paio di risposte, e cercherò di incorporarne un po' più tardi. – jonc

1

mesi unione e shortMonths in un unico array ordinato e fare una ricerca binaria sulla matrice. O uniscili entrambi in un Set (HashSet) e usa contiene. Cambia tutti i nomi dei mesi in minuscolo e fai lo stesso con il valore di ricerca, se vuoi essere insensibile alle maiuscole/minuscole.

Se si desidera essere in grado di recuperare il numero del mese, unirli tutti in una mappa (HashMap) con il valore corrispondente al numero del mese.

1

HashSet è una buona soluzione generica, ma penso che tu possa fare di meglio. Dai un'occhiata alla prima lettera dei mesi - jfmasond - se fai il pre-filtro su questi, e fai solo il controllo HashSet se passa, si prenderà cura di un enorme numero di scenari 'return false'.

Puoi impostarlo in due modi: un modo molto semplice per farlo è usare un'istruzione switch, sebbene una tabella di ricerca sia più veloce. Nota anche che devi solo controllare se il primo carattere è tra a e s, quindi una tabella di ricerca non deve avere lo spazio di codice completo Unicode (o UTF-8 a seconda dei requisiti).

Per rendere questo ancora più efficace, è possibile costruire la tabella di ricerca in modo che contenga i primi 2 caratteri di ogni mese: la tabella di ricerca risultante non è troppo grande e questo ridurrebbe drasticamente il numero di parole necessarie essere controllato contro l'hashset.

PS: prima di eseguire questa operazione, è necessario eseguire un po 'di profilazione e accertarsi che questa sia l'area del codice che rappresenta effettivamente il collo di bottiglia.

+0

Bel pensiero sulla tabella di ricerca. Tuttavia, l'intero progetto non è ancora arrivato, quindi rimarrò sulla tabella di ricerca fino a quando non riuscirò a creare un profilo migliore – jonc

+0

in sostanza descrivendo la creazione della tua macchina di stato molto specifica (che ho commentato all'OP prima di notare il tuo risposta). In Java una dichiarazione * switch * costruita con cura deve essere più veloce di una ricerca tabella: in pratica si desidera che l'istruzione switch diventi l'opcode * tableswitch * JVM (non quello * lookupswitch *, che è più lento). Facendo questo, schivi la tabella di ricerca e quindi sarai più veloce (meno spesso invalidando le cache, ecc.).Ora ovviamente dubito che l'OP abbia davvero bisogno di questo tipo di ottimizzazioni nel suo caso. – SyntaxT3rr0r

+0

@webinator - buone informazioni - Non ho fatto abbastanza spelunking nel bytecode Java, ma la tua descrizione ha un senso. Sono interessato a ciò che causa l'interpretazione del commutatore di tableswitch vs lookupswitch nell'intervallo - I'll look up. –