2011-05-10 3 views
40

¿Hay un método flatten en Guava, o una forma fácil de convertir un Iterable<Iterable<T>> en un Iterable<T>?Aplanamiento de un Iterable <Iterable<T>> en Guava

Tengo un Multimap<K, V> [sourceMultimap] y quiero devolver todos los valores donde la clave coincida con algún predicado [keyPredicate]. Así que en el momento que tengo:

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

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

He mirado a través de los documentos de guayaba, pero nada saltó. Estoy comprobando que no me he perdido nada. De lo contrario, extraeré mis tres líneas en un método genérico abreviado y lo dejaré así.

Respuesta

72

Los Iterables.concat method satisface ese requisito:

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

Muchas gracias, no sé cómo me lo perdí! –

+6

Supongo que esto se debe a que esta es una concatenación de un solo nivel, no se aplana realmente :) –

+0

Además, si se está generando una colección a partir de una transformación de guayaba, puede usar FluentIterable transformAndConcat: http: //docs.guava-libraries.googlecode. com/git/javadoc/com/google/common/collect/FluentIterable.html # transformAndConcat (com.google.common.base.Function) –

2

A partir de Java 8, se puede hacer esto sin guayaba. Es un poco torpe porque Iterable doesn't directly provide streams requiere el uso de StreamSupport, pero no requiere crear una nueva colección como el código en la pregunta.

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

No se ajusta a mis necesidades, porque mi iterador es flojo, pero toda la pereza se pierde cuando se convierte tal iterador para transmitir. – odiszapc

+0

@odiszapc No estoy seguro de lo que quieres decir. Iterable.spliterator() simplemente devuelve un Spliterator envolviendo Iterable.iterator(); no se dibujan elementos hasta que comience la operación de la terminal de la secuencia. De manera similar, StreamSupport.stream está documentado explícitamente para no comenzar a consultar al spliterator hasta que comience la operación del terminal. Entonces creo que estás diciendo que tu nivel superior _iterable_ es flojo, y quieres retrasar la invocación de iterator() en él? En ese caso, use la sobrecarga StreamSupport.stream tomando un proveedor ('StreamSupport.stream ((-) -> foo.spliterator(), false)'). –

+2

@odiszapc De lo contrario, me gustaría un ejemplo mínimo que reproduzca por qué esta respuesta no funciona, si tiene tiempo para hacer una, porque aprenderé algo de ella. –

Cuestiones relacionadas