2009-07-26 19 views
47

Devo davvero implementarla da solo?Compattare una lista array con una nuova dimensione

private void shrinkListTo(ArrayList<Result> list, int newSize) { 
    for (int i = list.size() - 1; i >= newSize; --i) 
    list.remove(i); 
} 
+0

FWIW il modo più ordinato di scrivere che è ", mentre lunghezza> limite, rimuovere l'ultimo attivo e "! – Fattie

risposta

95

Creare un sublist con la gamma di elementi che si desidera rimuovere e quindi chiamare clear sulla lista restituita.

list.subList(23, 45).clear() 

Questo approccio è indicato come un idioma nella documentazione sia per List e ArrayList.


Ecco un'unità completamente testati esempio di codice!

// limit yourHappyList to ten items 
int k = yourHappyList.size(); 
if (k > 10) 
    yourHappyList.subList(10, k).clear(); 
    // sic k, not k-1 
+0

+1 probabilmente l'implementazione più veloce che mantiene il puntatore all'originale – akf

+0

Confermato dalla documentazione ufficiale https://docs.oracle.com/javase/6/docs/api/java/util/List.html#subList(int,%20int). "Ad esempio, il seguente idioma rimuove un intervallo di elementi da un elenco: list.subList (from, to) .clear();" –

4

uso ArrayList#removeRange() metodo:

protetta removeRange void (int fromIndex, int toIndex)

Rimuove da questa lista tutti gli elementi il ​​cui indice è tra fromIndex, inclusivo, e toIndex , esclusivo. Sposta tutti gli elementi successivi a sinistra (riduce il loro indice). Questa chiamata accorcia la lista per (toIndex - fromIndex) elementi. (Se toIndex == fromIndex, questa operazione non ha effetto.)

quindi utilizzare ArrayList#trimToSize() metodo:

Trim la capacità di questa istanza ArrayList essere formato corrente del lista. Un'applicazione può utilizzare questa operazione per ridurre al minimo l'archiviazione di un'istanza ArrayList.

+0

downvotes senza spiegazione sono inutili – dfa

+6

metodo protetto ??? – ripper234

+0

se non riesci a creare una sottoclasse, prova la subList (controlla la mia seconda risposta) – dfa

0

C'è un'altra considerazione. Si consiglia di evitare l'utilizzo di un ArrayList nella propria firma del metodo e lavorare invece all'interfaccia List, poiché si collega all'implementazione ArrayList, rendendo difficili le modifiche lungo la linea se si scopre che, ad esempio, un LinkedList è più adatto alle tue esigenze. Prevenire questo accoppiamento stretto ha un costo.

Un approccio alternativo potrebbe essere la seguente:

private void shrinkListTo(List<Result> list, int newSize) { 
    list.retainAll(list.subList(0, newSize); 
} 

Purtroppo, il metodo List.retainAll() è facoltativo per le sottoclassi di implementare, quindi si avrebbe bisogno di un catchUnsupportedOperationException, e poi fare qualcosa di diverso.

private void shrinkListTo(List<Result> list, int newSize) { 
    try { 
    list.retainAll(list.subList(0, newSize); 
    } catch (UnspportedOperationException e) { 
    //perhaps log that your using your catch block's version. 
    for (int i = list.size() - 1; i >= newSize; --i) 
     list.remove(i); 
    } 
    } 
} 

Questo non è semplice come il tuo originale. Se non sei legato all'istanza della Lista in cui stai passando, puoi facilmente restituire una nuova istanza chiamando lo subList(int start, int end) e non avresti nemmeno bisogno di creare un metodo. Questa sarebbe anche un'implementazione più veloce, in quanto (in Java 6) si otterrebbe un'istanza di AbstractList.SubList che contiene l'elenco, un offset e una dimensione. Non ci sarebbe bisogno di iterare.

Se siete interessati negli argomenti per la codifica di interfacce, invece di classi, vedere this favorite article by Allen Holub

+1

usando .retainAll() sarà davvero inefficiente. dovrà prendere O (n^2) perché per ogni elemento della lista, deve passare attraverso la sottolista per controllarlo (non sa che è una sottolista) – newacct

7

in alternativa è possibile utilizzare subList metodo:

public static <T> List<T> shrinkTo(List<T> list, int newSize) { 
    return list.subList(0, newSize - 1); 
} 
+0

sì, ma ciò non ha alcun effetto sull'elenco originale. forse gli elementi da rimuovere non sono più necessari e vuole liberarli; questo metodo non lo farebbe. – newacct

+1

il GC si prenderà cura di esso – dfa

3

La mia soluzione:

public static void shrinkTo(List list, int newSize) { 
    int size = list.size(); 
    if (newSize >= size) return; 
    for (int i = newSize; i < size; i++) { 
     list.remove(list.size() - 1); 
    } 
} 

Basta usare:

shrinkTo(yourList, 6); 
+0

Sembra che mi lavori. Grazie! –

+0

La complessità sarà O (n * k); k = i numeri devono essere rimossi. Nel peggiore dei casi sarebbe andata fino a O (n2). –

Problemi correlati