Y a-t-il une raison pour laquelle il y a
Lists.transform()
mais non
Lists.filter()
?
Comment filtrer correctement une liste? je pourrais utiliser
new ArrayList(Collection2.filter())
bien sûr, mais de cette façon il n'est pas garanti que ma commande reste la même, si je comprends bien.
List.newArrayList(Iterables.filter(...))
, il devrait direLists.newArrayList(Iterables.filter(...))
.Réponses:
Il n'a pas été implémenté car il exposerait un grand nombre périlleux de méthodes lentes, telles que #get (index) sur la vue de liste renvoyée (invitant des bogues de performances). Et ListIterator serait également difficile à implémenter (même si j'ai soumis un correctif il y a des années pour couvrir cela).
Étant donné que les méthodes indexées ne peuvent pas être efficaces dans la vue Liste filtrée, il est préférable d'utiliser simplement un Iterable filtré, qui ne les a pas.
la source
filter
signifie systématiquement une vue (avec le comportement que cela implique) que ce soitIterables.filter
,Sets.filter
etc. Comme il seIterables.filter
combine facilement aveccopyOf
n'importe lequelImmutableCollection
, je trouve que c'est un bon compromis de conception (vs proposer des méthodes et des noms supplémentaires, commefilteredCopy
ou autre) , pour des combinaisons d'utilitaires simples).Vous pouvez utiliser
Iterables.filter
, ce qui maintiendra définitivement la commande.Notez qu'en construisant une nouvelle liste, vous allez copier les éléments (juste des références, bien sûr) - donc ce ne sera pas une vue en direct sur la liste d'origine. Créer une vue serait assez délicat - considérez cette situation:
Predicate<StringBuilder> predicate = /* predicate returning whether the builder is empty */ List<StringBuilder> builders = Lists.newArrayList(); List<StringBuilder> view = Lists.filter(builders, predicate); for (int i = 0; i < 10000; i++) { builders.add(new StringBuilder()); } builders.get(8000).append("bar"); StringBuilder firstNonEmpty = view.get(0);
Cela devrait parcourir toute la liste d'origine, en appliquant le filtre à tout. Je suppose que cela pourrait exiger que la correspondance de prédicat ne change pas pendant la durée de vie de la vue, mais ce ne serait pas entièrement satisfaisant.
(Ceci est juste une supposition, remarquez. Peut-être que l'un des responsables de Guava expliquera la vraie raison :)
la source
Collections2.filter.iterator
appelle justeIterables.filter
, donc le résultat est le même.Iterables.filter
version juste pour plus de clarté.view.size()
quelque part plus tard dans le code :)Ce n'est pas vrai.
Collections2.filter()
est une fonction évaluée paresseusement - elle ne filtre pas réellement votre collection tant que vous ne commencez pas à accéder à la version filtrée. Par exemple, si vous parcourez la version filtrée, les éléments filtrés sortiront de l'itérateur dans le même ordre que votre collection d'origine (moins ceux filtrés, évidemment).Peut-être pensiez-vous qu'il effectue le filtrage à l'avance, puis vide les résultats dans une collection arbitraire et non ordonnée d'une certaine forme - ce n'est pas le cas.
Ainsi, si vous utilisez la sortie de
Collections2.filter()
comme entrée d'une nouvelle liste, votre commande d'origine sera conservée.En utilisant les importations statiques (et la
Lists.newArrayList
fonction), cela devient assez succinct:Notez que tout
Collections2.filter
ne sera pas avec impatience parcourir la collection sous - jacente,Lists.newArrayList
sera - il extraira tous les éléments de la collection filtrée et les copier dans un nouveauArrayList
.la source
List filteredList = newArrayList(filter(originalList, new Predicate<T>() { @Override public boolean apply(T input) { return (...); } }));
ou ie.List filteredList = newArrayList(filter(originalList, Predicates.notNull()));
Comme mentionné par Jon, vous pouvez utiliser
Iterables.filter(..)
ouCollections2.filter(..)
et si vous n'avez pas besoin d'une vue en direct, vous pouvez utiliserImmutableList.copyOf(Iterables.filter(..))
ouLists.newArrayList( Iterables.filter(..))
et oui, la commande sera maintenue.Si vous êtes vraiment intéressé par le pourquoi de la partie, vous pouvez visiter https://github.com/google/guava/issues/505 pour plus de détails.
la source
Pour résumer ce que les autres ont dit, vous pouvez facilement créer un wrapper générique pour filtrer les listes:
public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) { return Lists.newArrayList(Iterables.filter(userLists, predicate)); }
la source