2011-05-10 4 views
40

Existe-t-il une méthode flatten en goyave - ou un moyen facile de convertir un Iterable<Iterable<T>> en un Iterable<T>?Aplatissement d'un Iterable <Iterable<T>> dans Guava

J'ai un Multimap<K, V> [sourceMultimap] et je veux retourner toutes les valeurs où la clé correspond à un prédicat [keyPredicate]. J'ai donc pour le moment:

Iterable<Collection<V>> vals = Maps.filterKeys(sourceMultimap.asMap(), keyPredicate).values(); 

Collection<V> retColl = ...; 
for (Collection<V> vs : vals) retColl.addAll(vs); 
return retColl; 

J'ai regardé les docs de Guava, mais rien n'a sauté. Je vérifie juste que je n'ai rien manqué. Sinon, je vais extraire mes trois lignes dans une méthode générique courte et aplatie.

Répondre

72

Le Iterables.concat method satisfait à cette exigence:

public static <T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs) 
+0

Merci beaucoup - je ne sais pas comment je l'ai manqué! –

+6

Je suppose que c'est parce que ce n'est qu'une concaténation de niveau, pas vraiment aplatie :) –

+0

Aussi si une collection est générée à partir d'une transformée de goyave, vous pouvez utiliser FluentIterable transformAndConcat: http: //docs.guava-libraries.googlecode. com/git/javadoc/com/google/commun/collect/FluentIterable.html # transformAndConcat (com.google.common.base.Function) –

2

A partir de Java 8, vous pouvez le faire sans goyave. C'est un peu maladroit car Iterable doesn't directly provide streams, nécessitant l'utilisation de StreamSupport, mais il ne nécessite pas de créer une nouvelle collection comme le code dans la question.

private static <T> Iterable<T> concat(Iterable<? extends Iterable<T>> foo) { 
    return() -> StreamSupport.stream(foo.spliterator(), false) 
     .flatMap(i -> StreamSupport.stream(i.spliterator(), false)) 
     .iterator(); 
} 
+0

Ne correspond pas à mes besoins, parce que mon itérateur est paresseux, mais toute paresse est perdue lors de la conversion un tel itérateur pour diffuser. – odiszapc

+0

@odiszapc Je ne suis pas sûr de ce que vous voulez dire. Iterable.spliterator() renvoie juste un wrapper Spliterator Iterable.iterator(); aucun élément n'est dessiné jusqu'à ce que l'opération du terminal commence. De même, StreamSupport.stream est explicitement documenté pour ne pas commencer à interroger le séparateur jusqu'à ce que l'opération du terminal commence. Donc je pense que vous dites que votre _iterable_ de niveau supérieur est paresseux, et que vous voulez retarder l'appel de iterator() dessus? Dans ce cas, utilisez la surcharge StreamSupport.stream en prenant un fournisseur ('StreamSupport.stream (() -> foo.spliterator(), false)'). –

+2

@odiszapc Sinon, je serais intéressé par un exemple minimal qui reproduirait pourquoi cette réponse ne fonctionne pas, si vous avez le temps d'en faire une, car j'y apprendrai quelque chose. –

Questions connexes