2011-10-21 27 views
6

Por ejemplo, he puesto de figuras geométricas:¿Cómo crear una colección desde Iterable en java?

Set<Figure> figures; 

Hay dos tipos de la Figura: cuadrado y el círculo.

quiero conseguir un conjunto de cuadrados usando colecciones de Google:

Iterables.filter(figures,squarePredicate); 

Pero el regreso método de filtro Iterable ... ¿Cómo se puede crear un conjunto de Iterable? (sin utilizar bucle en Iterable)

Respuesta

14

Creo que necesita replantearse sus requisitos. Necesitas un conjunto de cuadrados. ¿Por qué?

Un conjunto te ofrece unicidad e iteración, nada más. Tiene unicidad en su Iterable, porque la fuente es un conjunto y puede iterar sobre los elementos en un Iterable. Entonces, ¿por qué necesitarías el set?

Existen solo dos razones posibles: o bien está trabajando con una API que necesita un parámetro Establecer (o Colección), o necesita mostrar de alguna manera el tamaño del Conjunto.

En estos casos, use Sets.newHashSet(iterable) para crear un conjunto (por un lado, por supuesto, que requiere una iteración completa, por otro lado: necesitará una iteración completa en un punto cuando esté iterando sobre los valores, ¿Por qué no hacerlo ahora?). De lo contrario, solo usa Iterable y olvídate de un conjunto.

+0

Este código es, por ejemplo. Tengo un conjunto de objetos de dos tipos. Quiero filtrar un tipo de objetos con las colecciones de google y luego obtener un segundo tipo de objetos con la substracción de conjuntos. –

+0

Pequeño error tipográfico: Sets.newHash ** S ** et (iterable) – tashuhka

+0

@tashuhka corregido, gracias –

1

Quizás intente CollectionUtils.filter() de apache collection utils instead? Puede usarlo en un conjunto o usar la colección resultante en el constructor de conjuntos.

+0

OP hizo especie de estado "a través de Google Colecciones ". –

+0

La pregunta es sobre Guava, no Commons/Colecciones. Y el problema es el mismo: necesita una iteración completa para aplicar el filtro. –

+0

Creo que estaba describiendo el problema que se encuentra con la colección de google en lugar de decir que es obligatorio usarlo. Solo sugiero ir en otra dirección en caso de que no sea obligatorio. Sólo una sugerencia. – kgautron

5

Guava Iterables.filter() devuelve deliberadamente una "vista" Iterable. Hay dos ventajas de este enfoque:

  • sólo iterar sobre los elementos cuando realmente se necesita (por ejemplo, puede cadena Iterables.filter() y Iterables.transform() llama, e iterar una sola vez al final)
  • puede crear la colección adecuada desde la vista, usando algo como ImmutableSet.copyOf(Iterables.filter(..., ...)), Sets.newHashSet(Iterables.filter(..., ...)) o Lists.newArrayList(Iterables.filter(..., ...)). Iterables.filter() le permite elegir la colección precisa necesaria, en lugar de devolver una colección arbitraria.

También he notado que parece que utilizar Iterables.filter(Iterable unfiltered, Predicate predicate) con un predicado para filtrar instancias de un tipo específico. También podría estar interesado en la sobrecarga Iterables.filter(Iterable unfiltered, Class type), que filtra todas las instancias del tipo dado y devuelve un Iterable con el tipo genérico más específico. Esto te permite evitar lanzamientos incómodos.

+0

gracias! muy informativo –

7

Si tiene un Set, puede usar Sets.filter en lugar de Iterables.filter y obtener un resultado Set. Esa Set es una vista en vivo, como el resultado de Iterables.filter, pero tiene propiedades Set, como un método rápido contains.

para crear una copia que contiene sólo los elementos que coinciden con el predicado, puede utilizar ImmutableSet.copyOf o Sets.newHashSet como han sugerido otros.

1

Puede filtrar un conjunto y recoger en otro conjunto con Java 8 corrientes:

Set<Number> integers = numbers.stream() 
    .filter(x -> x instanceof Integer) 
    .collect(Collectors.toSet()); 

El conjunto devuelto es una copia, no es una vista en vivo.

Tenga en cuenta que, a diferencia de, por ejemplo, Guava FluentIterable.filter, el conjunto resultante es Set<Integer> porque Java no sabe que ha filtrado todos los no enteros. Si necesita un Set<Integer>, you have to map after filtering.

Set<Integer> integers = numbers.stream() 
    .filter(x -> x instanceof Integer) 
    .map(x -> (Integer)x) 
    .collect(Collectors.toSet()); 

(Se puede combinar el filtro y el mapa en un flatMap, pero eso sería introducir un objeto de secuencia temporal por entero, y no es más concisa.)

Cuestiones relacionadas