2009-07-26 9 views
47

Ai-je vraiment besoin de l'implémenter moi-même?Réduire une ArrayList à une nouvelle taille

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

FWIW la plus sommaire d'écrire qui est « tout longueur> limite, supprime le dernier sur e "! – Fattie

Répondre

95

Créer une sublist avec la gamme d'éléments que vous souhaitez supprimer, puis appeler clear sur la liste retournée.

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

Cette approche est mentionnée comme un idiome dans la documentation pour les List et ArrayList.


Voici un exemple de code entièrement testé à l'unité!

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

+1 probablement l'implémentation la plus rapide qui retient le pointeur vers l'original – akf

+0

Confirmé par la documentation officielle https://docs.oracle.com/javase/6/docs/api/java/util/List.html#subList(int,%20int). "Par exemple, l'idiome suivant supprime une plage d'éléments d'une liste: list.subList (from, to) .clear();" –

4

utilisation ArrayList#removeRange() méthode:

removeRange void (int fromIndex, int toIndex)

protégé

supprime de la liste de tous les éléments dont l'indice est compris entre fromIndex, inclusivement, et toIndex , exclusif. Décale tous les éléments suivants vers la gauche (réduit leur indice). Cet appel raccourcit la liste des éléments (toIndex - fromIndex). (Si toIndex == fromIndex, cette opération n'a pas d'effet.)

puis utilisez la méthode ArrayList#trimToSize():

la capacité de Trims cette instance ArrayList être la taille actuelle de la liste. Une application peut utiliser cette opération pour minimiser le stockage d'une instance ArrayList.

+0

downvotes sans explication sont inutiles – dfa

+6

méthode protégée ??? – ripper234

+0

si vous ne pouvez pas sous-classe, essayez subList (vérifier ma deuxième réponse) – dfa

0

Il y a une autre considération. Vous voudrez peut-être éviter d'utiliser un ArrayList dans votre signature de méthode, et travailler à l'interface List, car il vous lie à l'implémentation ArrayList, ce qui complique les choses si vous trouvez, par exemple, qu'un LinkedList est plus adapté à vos besoins. Empêcher ce couplage serré a un coût.

Une autre approche pourrait ressembler à ceci:

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

Malheureusement, la méthode List.retainAll() est facultative pour les sous-classes pour mettre en œuvre, de sorte que vous devez catch un UnsupportedOperationException, puis faire autre chose.

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

Ce n'est pas aussi simple que votre original. Si vous n'êtes pas lié à l'instance de la liste que vous transmettez, vous pouvez tout aussi bien renvoyer une nouvelle instance en appelant le subList(int start, int end), et vous n'aurez même pas besoin de créer une méthode. Ce serait aussi une implémentation plus rapide, car (en Java 6), vous obtiendriez une instance d'un AbstractList.SubList qui contient votre liste, un offset dedans et une taille. Il n'y aurait pas besoin d'itération.

Si vous êtes intéressé par les arguments pour le codage aux interfaces des classes au lieu, voir this favorite article by Allen Holub

+1

en utilisant .retainAll() va être vraiment inefficace. il faudra prendre O (n^2) car pour chaque élément de la liste, il doit passer par la sous-liste pour le vérifier (il ne sait pas qu'il s'agit d'une sous-liste) – newacct

7

Vous pouvez également utiliser la méthode subList:

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

oui mais cela n'affecte pas la liste d'origine. peut-être que les éléments à enlever ne sont plus nécessaires et il veut les libérer; cette méthode ne permettrait pas cela. – newacct

+1

le GC s'en occupera – dfa

3

Ma solution:

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

utiliser Just:

shrinkTo(yourList, 6); 
+0

Ça me semble fonctionner. Je vous remercie! –

+0

La complexité sera O (n * k); k = les nombres doivent être supprimés. Dans le pire des cas, cela irait jusqu'à O (n2). –

Questions connexes