una tiempo real mostrar mientras metodo lista hacer filtros filtro filtrar filtrada escribes elementos ejemplo datos como busqueda buscar java generics guava iterable

tiempo - filtros java ejemplo



Filtrado de listas de tipos genéricos. (2)

Las listas o los Iterables se pueden filtrar fácilmente usando el filter(Iterable<?> unfiltered, Class<T> type) . Esta operación realiza dos tareas: la lista se filtra y se transforma en una secuencia del tipo T.

Muy a menudo, sin embargo, termino con Iterables<Something<?>> y quiero obtener una subsecuencia de Iterables<Something<T>> para algunos T. especializados

Está claro que Guava no puede resolver este problema fuera de la caja debido al borrado de tipo: Something<T> no proporciona ninguna información directa sobre su T.

Digamos que tengo algo como S<? extends Number> S<? extends Number> . Si soy capaz de definir algún predicado que me dice si S<?> puede convertir a S<Double> puedo usarlo como archivador:

<T extends Number> Predicate<S<?>> isOfType(Class<N> type) {...}

con:

Iterable<S<?>> numbers; Iterable<S<?>> filtered = Iterable.filter(numbers, isOfType(Double.class));

Esto realiza la tarea de filtrado pero pierde el paso de transformación. Si creo que mi Predicado funciona bien, incluso puedo pensar en lanzar:

Iterable<S<Double>> doubles = (Iterable<S<Double>>) filtered;

Pero esto expone alguna operación de reparto feo.

Como alternativa, puedo proporcionar una Function<S<?>, S<Double>> para realizar el lanzamiento. En contraste con Class.cast() sin embargo, no debe lanzar una ClassCastException sino simplemente devolver un null si el elemento no puede ser lanzado (o transformado). De esta manera, la secuencia se puede convertir sin ninguna conversión explícita:

<T extends Number> Function<S<?>, S<T>> castOrNull(Class<N> type) {...} Iterable<S<Double>> doubles = Iterable.filter(numbers, castOrNull(Double.class));

Pero la lista no está realmente filtrada: en su lugar, todavía contiene objetos nulos para cada elemento que no se pudo convertir o convertir a S<Double> . Pero esto puede resolverse fácilmente mediante un paso de filtrado adicional como:

Iterable<S<Double>> doubles = Iterables.filter(doubles, Predicates.notNull());

La segunda solución me parece mucho más inteligente. La Function que se definirá puede realizar una conversión (que oculta la operación no verificada) o puede crear un nuevo objeto S<T> si es necesario.

La pregunta restante es: ¿Existe alguna forma más inteligente de realizar la conversión y el filtrado necesarios en un solo paso? Simplemente puedo definir alguna función de utilidad como:

<I,O> Iterables<O> convert( Iterables<O> input, Function<? super I, ? extends O> convert, Predicate<? super O> filter); <I,O> Iterables<O> convert( Iterables<O> input, Function<? super I, ? extends O> convert);

Donde la segunda función es un atajo de la primera con un Predicates.notNull() ;

Pero también vale la pena tener la primera función, ya que el predicado no es necesario. Predicates.notNull() .

Imagina un Iterable<Iterable<? extends Number>> Iterable<Iterable<? extends Number>> . La función del convertidor Function<Iterable<? extends Number>, Iterable<Double>> Function<Iterable<? extends Number>, Iterable<Double>> puede devolver simplemente una secuencia filtrada que puede estar vacía en lugar de devolver un valor nulo. El filtro adicional puede finalmente eliminar secuencias vacías utilizando Iterables.isEmpty() .


El enfoque monádico de este problema es definir una operación que transforma un iterable en un iterable de iterables, al definir una función de transformación que para un objeto de tipo T , devuelve un objeto de tipo Iterable<T> . A continuación, puede concatenar cada iterable para formar una sola de nuevo. Esta combinación de un mapa seguido de una concatenación se llama concatMap en Haskell y flatMap en Scala, y estoy seguro de que tiene otros nombres en otros lugares.

Para implementar esto, primero creamos una función que transforma su S<? extends Number> S<? extends Number> a Iterable<S<Double>> . Esto es muy similar a su función existente, pero nuestro caso de éxito es iterable de uno, que contiene nuestra S , y el caso de falla (nuestro estado nulo) es un iterable vacío.

<T extends Number> Function<S<?>, Iterable<S<T>>> castOrNull(Class<T> type) { return new Function<S<?>, Iterable<S<T>>> { @Override public Iterable<S<T>> apply(S<?> s) { Object contained = s.get(); if (!(contained instanceof T)) { return ImmutableSet.of(); } return ImmutableSet.of(new S<T>(contained)); } }; }

Luego aplicamos esto al iterable original como usted lo especificó anteriormente.

Iterable<Iterable<S<Double>>> doubleIterables = Iterables.map(numbers, castOrNull(Double.class));

Luego podemos concatenar todos estos juntos para producir una iterable de nuevo, que tiene todos los valores deseados y ninguno de los que queremos eliminar.

Iterable<S<Double>> doubles = Iterables.concat(doubleIterables);

Descargo de responsabilidad: no he intentado compilar esto. Es posible que tenga que jugar con los genéricos para que funcione.


El lenguaje Scala en su marco de colecciones ofrece una funcionalidad similar a la guayaba. Tenemos la clase Opción [T] que se puede considerar como una colección de un solo elemento como máximo. Entre los métodos simples de filtrado o transformación hay un método que realiza ambas operaciones a la vez. Se espera que la función de transformación provista devuelva un valor de la clase Option. Luego fusiona el contenido de los objetos Option devueltos en una colección. Creo que puedes implementar una funcionalidad similar en Java.

Estaba pensando en este problema hace algún tiempo porque primero aplicar la transformación y luego filtrar requiere pasar la colección dos veces. Entonces alguien me iluminó que puedo transformar y filtrar el iterador de esta colección. En este caso, la colección se recorre una vez y puede aplicar tantos filtros y transformaciones como desee.