2010-04-15 7 views
29

Qual è il modo più efficiente per ridurre le maiuscole/minuscole a ogni elemento di un elenco o di un set?Come minimizzare efficacemente ogni elemento di una raccolta?

La mia idea per una lista:

final List<String> strings = new ArrayList<String>(); 
strings.add("HELLO"); 
strings.add("WORLD"); 

for(int i=0,l=strings.size();i<l;++i) 
{ 
    strings.add(strings.remove(0).toLowerCase()); 
} 

Esiste un modo migliore, più veloce? Come sarebbe questo esempio per un Set? Poiché non esiste attualmente alcun metodo per applicare un'operazione a ciascun elemento di un Set (o Elenco), può essere fatto senza creare un Set temporaneo aggiuntivo?

Qualcosa del genere sarebbe bello:

Set<String> strings = new HashSet<String>(); 
strings.apply(
    function (element) 
    { this.replace(element, element.toLowerCase();) } 
); 

Grazie,

risposta

22

Questa sembra una soluzione abbastanza pulita per le liste. Dovrebbe permettere che la particolare implementazione List venga utilizzata per fornire un'implementazione ottimale sia per l'attraversamento della lista - in tempo lineare - sia per la sostituzione della stringa - in tempo costante.

public static void replace(List<String> strings) 
{ 
    ListIterator<String> iterator = strings.listIterator(); 
    while (iterator.hasNext()) 
    { 
     iterator.set(iterator.next().toLowerCase()); 
    } 
} 

questo è il meglio che posso venire con per il set. Come altri hanno già detto, l'operazione non può essere eseguita sul posto nel set per una serie di motivi. Potrebbe essere necessario posizionare la stringa in minuscolo in una posizione diversa nel set rispetto alla stringa che sta sostituendo. Inoltre, la stringa minuscola non può essere aggiunta al set se è identica a un'altra stringa minuscola che è già stata aggiunta (ad esempio "CIAO" e "Ciao" restituiranno entrambi "Ciao", che solo aggiunto al set una volta).

public static void replace(Set<String> strings) 
{ 
    String[] stringsArray = strings.toArray(new String[0]); 
    for (int i=0; i<stringsArray.length; ++i) 
    { 
     stringsArray[i] = stringsArray[i].toLowerCase(); 
    } 
    strings.clear(); 
    strings.addAll(Arrays.asList(stringsArray)); 
} 
+0

In riferimento alla prima soluzione: come si restituisce un ListIterator come Elenco? –

+0

@rookie, la tua domanda non è chiara. Stai chiedendo come utilizzare un ListIterator come elenco? Se è così, allora non puoi. Un Iterator non è una raccolta, ma un puntatore in una. – Jeremy

1

Questo è probabilmente più veloce:

for(int i=0,l=strings.size();i<l;++i) 
{ 
    strings.set(i, strings.get(i).toLowerCase()); 
} 
+2

Questo va bene per un 'ArrayList', ma la prestazione è' O (N^2) '' per un LinkedList'. –

+0

Sì. per il tuo, l'opposto è vero. –

+0

Scusa, per l'algoritmo originale, l'opposto è vero. –

4

Beh, non c'è una vera soluzione elegante a causa di due fatti:

  • String s in Java sono immutabili
  • Java non offre una vera e propria funzione map(f, list) come nelle lingue funzionali.

In termini asintotici, non è possibile ottenere un tempo di esecuzione migliore rispetto al metodo corrente. Dovrai creare una nuova stringa usando toLowerCase() e dovrai eseguire iterazioni da solo sull'elenco e generare ogni nuova stringa in minuscolo, sostituendola con quella esistente.

+0

E per di più non ci sono anche lambda in Java (finora) ... – Xaerxess

0

Non credo sia possibile eseguire la manipolazione in atto (senza creare un'altra raccolta) se si modificano le stringhe in modo che siano un set. Questo perché è possibile solo scorrere il Set utilizzando un iteratore o un ciclo per ogni ciclo e non è possibile inserire nuovi oggetti mentre lo fa (genera un'eccezione)

13

Si può fare questo con Google Collezioni:

Collection<String> lowerCaseStrings = Collections2.transform(strings, 
     new Function<String, String>() { 
      public String apply(String str) { 
       return str.toLowerCase(); 
      } 
     } 
    ); 
0

concernenti il ​​metodo di ListIterator nella soluzione accettata (di Matthew T. Staebler). Come sta usando ListIterator meglio del metodo qui?

public static Set<String> replace(List<String> strings) { 
    Set<String> set = new HashSet<>(); 
    for (String s: strings) 
     set.add(s.toLowerCase()); 
    return set; 
} 
59

Ancora un'altra soluzione, ma con Java 8:

List<String> result = strings.stream() 
          .map(String::toLowerCase) 
          .collect(Collectors.toList()); 
+0

se hai java 8, questa è la soluzione migliore nella discussione. – liltitus27

0

ero alla ricerca di roba simile, ma è stato bloccato perché il mio ArrayList oggetto non è stato dichiarato come GENERICA e era disponibile come grezzo Elenco tipo oggetto da qualche parte. Stavo solo ottenendo un ArrayList oggetto "_products". Quindi, quello che ho fatto è menzionato qui sotto e ha funzionato per me perfettamente ::

List<String> dbProducts = _products; 
    for(int i = 0; i<dbProducts.size(); i++) { 
     dbProducts.add(dbProducts.get(i).toLowerCase());   
    } 

vale a dire, in primo luogo ho preso i miei disponibili _Prodotti e ha fatto un generico oggetto lista (Come ho stavamo ottenendo solo le stringhe in stesso) quindi ho applicato il metodo toLowerCase() su elementi di lista che non funzionavano in precedenza a causa di un oggetto non generico ArrayList.

E il metodo toLowerCase() stiamo usando qui è di String classe.

String java.lang.String.toLowerCase()

non di ArrayList o oggetto classe.

Si prega di correggere se m sbagliato. Newbie in JAVA cerca indicazioni. :)

0

utilizzando Java 8 flusso parallelo diventa più veloce

List<String> output= new ArrayList<>(); 
List<String> input= new ArrayList<>(); 
input.add("A"); 
input.add("B"); 
input.add("C"); 
input.add("D"); 
input.stream().parallel().map((item) -> item.toLowerCase()) 
      .collect(Collectors.toCollection(() -> output)); 
+0

L'ordine delle stringhe nel risultato sarà diverso –

Problemi correlati