¿Cuál es la mejor manera de filtrar una colección Java?

Respuestas:

699

Java 8 ( 2014 ) resuelve este problema usando flujos y lambdas en una línea de código:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

Aquí hay un tutorial .

Use Collection#removeIfpara modificar la colección en su lugar. (Aviso: en este caso, el predicado eliminará los objetos que satisfagan el predicado):

persons.removeIf(p -> p.getAge() <= 16);

lambdaj permite filtrar colecciones sin escribir bucles o clases internas:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

¿Te imaginas algo más legible?

Descargo de responsabilidad: soy colaborador de lambdaj

Mario Fusco
fuente
34
Agradable, pero las importaciones estáticas ofuscan lo que está sucediendo. Como referencia, select / having / on son importaciones estáticas en ch.lambdaj.Lambda, mayor que org.hamcrest.Matchers
MikePatel
11
LambdaJ es realmente sexy, pero vale la pena señalar que implica una sobrecarga significativa (promedio de 2.6): code.google.com/p/lambdaj/wiki/PerformanceAnalysis .
Doc Davluz el
77
Aparentemente no funciona en Android: groups.google.com/forum/#!msg/lambdaj/km7uFgvSd3k/grJhgl3ik5sJ
Moritz
77
Realmente me gusta este ejemplo de LamdaJ ... similar a las funciones integradas de Lambda de .NET. ¿Y dónde puede beber una persona a los 16 años? Deberíamos considerar agregar una restricción de localización. : P
MAbraham1
3
removeIf ejemplo debería serpersons.removeIf(p -> p.getAge() <= 16);
vim
223

Suponiendo que está utilizando Java 1.5 y que no puede agregar Google Collections , haría algo muy similar a lo que hicieron los chicos de Google. Esta es una ligera variación en los comentarios de Jon.

Primero agregue esta interfaz a su base de código.

public interface IPredicate<T> { boolean apply(T type); }

Sus implementadores pueden responder cuando cierto predicado es verdadero de cierto tipo. Por ejemplo, si Testuviera Usere AuthorizedUserPredicate<User>implemente IPredicate<T>, AuthorizedUserPredicate#applydevuelve si el pase Userestá autorizado.

Luego, en alguna clase de utilidad, podrías decir

public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
    Collection<T> result = new ArrayList<T>();
    for (T element: target) {
        if (predicate.apply(element)) {
            result.add(element);
        }
    }
    return result;
}

Entonces, suponiendo que tiene el uso de lo anterior podría ser

Predicate<User> isAuthorized = new Predicate<User>() {
    public boolean apply(User user) {
        // binds a boolean method in User to a reference
        return user.isAuthorized();
    }
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);

Si el rendimiento en la verificación lineal es preocupante, entonces podría querer tener un objeto de dominio que tenga la colección de destino. El objeto de dominio que tiene la colección de destino tendría una lógica de filtrado para los métodos que inicializan, agregan y configuran la colección de destino.

ACTUALIZAR:

En la clase de utilidad (digamos Predicate), he agregado un método de selección con una opción para el valor predeterminado cuando el predicado no devuelve el valor esperado, y también una propiedad estática para los parámetros que se usarán dentro del nuevo IPredicate.

public class Predicate {
    public static Object predicateParams;

    public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
        Collection<T> result = new ArrayList<T>();
        for (T element : target) {
            if (predicate.apply(element)) {
                result.add(element);
            }
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
        T result = null;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
        T result = defaultValue;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }
}

El siguiente ejemplo busca objetos faltantes entre colecciones:

List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
    new IPredicate<MyTypeA>() {
        public boolean apply(MyTypeA objectOfA) {
            Predicate.predicateParams = objectOfA.getName();
            return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
                public boolean apply(MyTypeB objectOfB) {
                    return objectOfB.getName().equals(Predicate.predicateParams.toString());
                }
            }) == null;
        }
    });

El siguiente ejemplo busca una instancia en una colección y devuelve el primer elemento de la colección como valor predeterminado cuando no se encuentra la instancia:

MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
    return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));

ACTUALIZACIÓN (después del lanzamiento de Java 8):

Han pasado varios años desde que yo (Alan) publiqué esta respuesta por primera vez, y todavía no puedo creer que esté acumulando puntos SO para esta respuesta. En cualquier caso, ahora que Java 8 ha introducido cierres en el lenguaje, mi respuesta ahora sería considerablemente diferente y más simple. Con Java 8, no hay necesidad de una clase de utilidad estática distinta. Entonces, si desea encontrar el primer elemento que coincida con su predicado.

final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).findFirst();

La API de JDK 8 para opcionales tiene la capacidad de get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier)y orElseThrow(exceptionSupplier), así como otras funciones 'monádicos' tales como map, flatMapy filter.

Si desea simplemente recopilar todos los usuarios que coinciden con el predicado, utilice Collectorspara finalizar la secuencia en la colección deseada.

final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).collect(Collectors.toList());

Consulte aquí para obtener más ejemplos sobre cómo funcionan las transmisiones Java 8.

Alan
fuente
27
Sí, pero odio reinventar la rueda, nuevamente, repetidamente. Prefiero encontrar alguna biblioteca de utilidad que lo haga cuando quiera.
Kevin Wong
2
Esta no es la mejor manera en caso de que no desee la nueva colección. Use la metáfora del iterador de filtro, que puede ingresar en una nueva colección, o puede ser todo lo que necesita.
Josh
@Nestor: en una comprensión Scala, el filtrado sería mucho más simple:val authorized = for (user <- users if user.isAuthorized) yield user
Alan
¿Modifica esto la colección original o crea una nueva? Intenté usar este método y registré mis dos colecciones (la original y la que se devolvió del método), son lo mismo. @Alan
Rohan
1
@Rohan, esto no pretende mutar la colección original. Tenga en cuenta que la colección de resultados anterior está recién construida, y el método de filtro se agrega a la colección de resultados solo si se aplica el predicado.
Alan
92

Utilice CollectionUtils.filter (Collection, Predicate) , de Apache Commons.

Kevin Wong
fuente
3
esto está bien, pero no es genérico, y modifica la colección en su lugar (no es agradable)
Kevin Wong
2
Hay otros métodos de filtro en CollectionUtils que no modifican la colección original.
skaffman
42
En particular, el método que no modifica la colección en el lugar es org.apache.commons.collections.CollectionUtils # select (Collection, Predicate)
Eero
55
En Commons Collections v4, esto ahora usa Genéricos.
Justin Emery
1
Este método debe usarse con precaución ya que se basa (al menos en la implementación de commons-collections-3.2.1) en el método iterator.remove () que es opcional para las colecciones, por lo que en lugar de filtrar, por ejemplo, una matriz, podría obtener una UnsupportedOperationException.
user2417480
67

La "mejor" forma es una solicitud demasiado amplia. ¿Es "más corto"? "Lo más rápido"? "Legible"? ¿Filtrar en el lugar o en otra colección?

La forma más simple (pero no más legible) es iterarlo y usar el método Iterator.remove ():

Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
  Foo foo = it.next();
  if( !condition(foo) ) it.remove();
}

Ahora, para hacerlo más legible, puede envolverlo en un método de utilidad. Luego invente una interfaz IPredicate, cree una implementación anónima de esa interfaz y haga algo como:

CollectionUtils.filterInPlace(col,
  new IPredicate<Foo>(){
    public boolean keepIt(Foo foo) {
      return foo.isBar();
    }
  });

donde filterInPlace () itera la colección y llama a Predicate.keepIt () para saber si la instancia se mantendrá en la colección.

Realmente no veo una justificación para traer una biblioteca de terceros solo para esta tarea.

Vladimir Dyuzhev
fuente
66
Mi voto va por este: simplemente funciona, sin bibliotecas externas. Nunca me di cuenta de que crear una instancia de un iterador en realidad podría ser útil en comparación con el uso de la sintaxis para cada uno, o que podría eliminar elementos de una lista sin una excepción de modificación concurrente o algo así. :)
ZeroOne
1
Creo que esta es la mejor manera de usar la biblioteca Java estándar sin copiar. Para 1.8 habría la stream()función, pero no todos pueden jugar con los juguetes más nuevos: P
Populus
¿Esto también modifica la colección original? @ZeroOne
Rohan
Sí, por supuesto que sí, @Rohan. Pruébalo si no lo crees. ;)
ZeroOne
Jaja lo hice! Pero quiero conservar mi colección original. ¿Puedes sugerir una forma de hacer esto sin agregar una lib externa? @ZeroOne
Rohan
62

Considere Google Collections para un marco de Colecciones actualizado que admita genéricos.

ACTUALIZACIÓN : La biblioteca de colecciones de google ahora está en desuso. En su lugar, debe usar la última versión de Guava . Todavía tiene las mismas extensiones al marco de colecciones, incluido un mecanismo de filtrado basado en un predicado.

Heath Borders
fuente
Sí, conocía la biblioteca de colecciones de Google. La versión que estaba usando no tenía Collections2. Agregué una nueva respuesta a esta pregunta que enumera el método específico.
Kevin Wong
77
Kevin, Iterables.filter () e Iterators.filter () han estado allí desde el principio, y generalmente son todo lo que necesitas.
Kevin Bourrillion
28

Espera a Java 8:

List<Person> olderThan30 = 
  //Create a Stream from the personList
  personList.stream().
  //filter the element to select only those with age >= 30
  filter(p -> p.age >= 30).
  //put those filtered elements into a new List.
  collect(Collectors.toList());
gavenkoa
fuente
13
Ugh ... es muy detallado. ¿Por qué no podrían simplemente hacer: List <Person> result = personList.filter (p -> p.age> 30);
Kevin Wong
8
Para usar el filtro directamente en la Colección , debe usar removeIf call: download.java.net/jdk8/docs/api/java/util/…
gavenkoa
66
@KevinWong "detallado" describe más o menos todo el lenguaje que yo pensaría. ¿Al menos son consistentes?
Pícaro
55
¿Por qué no usar Collectors.toList () en la última parte?
Néstor Hernández Loli,
3
Aquí hay un enlace gavenkoa provisto que no 404. personList.removeIf(p -> p.age < 30);Menos detallado. Además, he oído hablar de comenzar la ejecución de API que aceptar y volver Streams en lugar de Collections porque Streams son muy útiles y rápido, pero ir a / de ellos es lento.
Capitán Man
11

Desde el lanzamiento temprano de Java 8, puede intentar algo como:

Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);

Por ejemplo, si tuviera una lista de enteros y quisiera filtrar los números que son> 10 y luego imprimir esos números en la consola, podría hacer algo como:

List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);
Josh M
fuente
11

Voy a tirar RxJava en el anillo, que también está disponible en Android . RxJava puede no ser siempre la mejor opción, pero le dará más flexibilidad si desea agregar más transformaciones a su colección o manejar errores durante el filtrado.

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
    .filter(new Func1<Integer, Boolean>() {
        public Boolean call(Integer i) {
            return i % 2 != 0;
        }
    })
    .subscribe(new Action1<Integer>() {
        public void call(Integer i) {
            System.out.println(i);
        }
    });

Salida:

1
3
5

Más detalles sobre RxJava filterse pueden encontrar aquí .

Brian Bowman
fuente
7

La puesta en marcha:

public interface Predicate<T> {
  public boolean filter(T t);
}

void filterCollection(Collection<T> col, Predicate<T> predicate) {
  for (Iterator i = col.iterator(); i.hasNext();) {
    T obj = i.next();
    if (predicate.filter(obj)) {
      i.remove();
    }
  }
}

El uso:

List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
  public boolean filter(MyObject obj) {
    return obj.shouldFilter();
  }
});
jon
fuente
2
Bien, pero prefiero la implementación de Alan porque obtienes una copia de la colección en lugar de alterarla. Además, el código de Alan es seguro para subprocesos, mientras que el tuyo no.
marcospereira
7

¿Qué tal un Java simple y directo?

 List<Customer> list ...;
 List<Customer> newList = new ArrayList<>();
 for (Customer c : list){
    if (c.getName().equals("dd")) newList.add(c);
 }

Simple, legible y fácil (¡y funciona en Android!) Pero si está utilizando Java 8, puede hacerlo en una sola línea:

List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());

Tenga en cuenta que toList () se importa estáticamente

Néstor Hernández Loli
fuente
7

Veamos cómo filtrar una lista JDK incorporada y una lista MutableList usando Eclipse Collections .

List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);

Si quisiera filtrar los números menores que 3, esperaría los siguientes resultados.

List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);

A continuación, le mostramos cómo puede filtrar utilizando un Java 8 lambda como Predicate.

Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));

Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));

Así es como puede filtrar usando una clase interna anónima como Predicate.

Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
    public boolean accept(Integer each)
    {
        return each < 3;
    }
};

Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));

Aquí hay algunas alternativas para filtrar listas JDK y Eclipse Collections MutableLists usando la fábrica de Predicados .

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

Aquí hay una versión que no asigna un objeto para el predicado, utilizando la fábrica Predicates2 en su lugar con el selectWithmétodo que toma a Predicate2.

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

A veces quieres filtrar en una condición negativa. Hay un método especial en Eclipse Collections para eso llamado reject.

Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));

El método partitiondevolverá dos colecciones, que contienen los elementos seleccionados por y rechazados por Predicate.

PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());

PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());

Nota: Soy un committer para Eclipse Collections.

Donald Raab
fuente
1
¿Cómo harías un removeIfen una lista o conjunto de primitivas?
Vivek Rao
La API para removeIf se agregó a colecciones primitivas en EC 9.1. eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/…
Donald Raab
5

Con ForEach DSL puedes escribir

import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;

Collection<String> collection = ...

for (Select<String> each : select(collection)) {
    each.yield = each.value.length() > 3;
}

Collection<String> result = $result();

Dada una colección de [The, quick, brown, fox, jumps, over, the, lazy, dog], esto resulta en [quick, brown, jumps, over, lazy], es decir, todas las cadenas de más de tres caracteres.

Todos los estilos de iteración admitidos por ForEach DSL son

  • AllSatisfy
  • AnySatisfy
  • Collect
  • Counnt
  • CutPieces
  • Detect
  • GroupedBy
  • IndexOf
  • InjectInto
  • Reject
  • Select

Para obtener más detalles, consulte https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach

akuhn
fuente
Eso es bastante inteligente! Sin embargo, ¡mucho trabajo para implementar una buena sintaxis Ruby-ish! Lo negativo es que su filtro no es una función de primera clase y, por lo tanto, no puede reutilizarse. Roll on closures ...
oxbow_lakes
Buen punto. Una forma de reutilizar el cuerpo del bucle es refactorizando el bucle en un método que tome la consulta de selección como parámetro. Sin embargo, eso no es tan útil y poderoso como los cierres reales, sin duda.
akuhn
5

Como java 9 Collectors.filtering está habilitado:

public static <T, A, R>
    Collector<T, ?, R> filtering(Predicate<? super T> predicate,
                                 Collector<? super T, A, R> downstream)

Por lo tanto, el filtrado debe ser:

collection.stream().collect(Collectors.filtering(predicate, collector))

Ejemplo:

List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
            .collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));
yanefedor
fuente
3

Esto, combinado con la falta de cierres reales, es mi mayor queja para Java. Honestamente, la mayoría de los métodos mencionados anteriormente son bastante fáciles de leer y REALMENTE eficientes; sin embargo, después de pasar tiempo con .Net, Erlang, etc., la comprensión de listas integrada a nivel de lenguaje hace que todo sea mucho más limpio. Sin adiciones a nivel de lenguaje, Java no puede ser tan limpio como muchos otros idiomas en esta área.

Si el rendimiento es una gran preocupación, las colecciones de Google son el camino a seguir (o escriba su propia utilidad de predicado simple). La sintaxis de Lambdaj es más legible para algunas personas, pero no es tan eficiente.

Y luego hay una biblioteca que escribí. Ignoraré cualquier pregunta con respecto a su eficiencia (sí, es tan malo) ... Sí, sé que está claramente basado en la reflexión, y no, en realidad no lo uso, pero funciona:

LinkedList<Person> list = ......
LinkedList<Person> filtered = 
           Query.from(list).where(Condition.ensure("age", Op.GTE, 21));

O

LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");
jdc0589
fuente
¿Enlace? Incluso si su biblioteca es ineficiente o de otra manera inutilizable, puede ser interesante observar si la fuente está disponible.
MatrixFrog
Hizo público el repositorio ( net-machine.com/indefero/p/jdclib/source/tree/master ). Estás interesado en el paquete de expresiones. El paquete de prueba tiene un probador con ejemplos de uso. Realmente nunca trabajé mucho en la interfaz de consulta de cadena mencionada anteriormente (no tenía ganas de escribir un analizador real), por lo que la interfaz de consulta explícita en el probador es el camino a seguir.
jdc0589
2

JFilter http://code.google.com/p/jfilter/ es el más adecuado para sus necesidades.

JFilter es una biblioteca de código abierto simple y de alto rendimiento para consultar la colección de beans Java.

Características clave

  • Soporte de propiedades de colección (java.util.Collection, java.util.Map y Array).
  • Soporte de colección dentro de colección de cualquier profundidad.
  • Soporte de consultas internas.
  • Soporte de consultas parametrizadas.
  • Puede filtrar 1 millón de registros en unos 100 ms.
  • El filtro (consulta) se proporciona en formato json simple, es como las consultas de Mangodb. Los siguientes son algunos ejemplos.
  • {"id": {"$ le": "10"}
    • donde la propiedad id del objeto es menor que igual a 10.
  • {"id": {"$ in": ["0", "100"]}}
    • donde la propiedad de id de objeto es 0 o 100.
  • {"lineItems": {"lineAmount": "1"}}
    • donde la propiedad de colección lineItems de tipo parametrizado tiene lineAmount igual a 1.
  • {"$ y": [{"id": "0"}, {"billingAddress": {"city": "DEL"}}]}
    • donde la propiedad id es 0 y la propiedad billingAddress.city es DEL.
  • {"lineItems": {"tax": {"key": {"code": "GST"}, "value": {"$ gt": "1.01"}}}}
    • donde la propiedad de colección lineItems del tipo parametrizado que tiene la propiedad del tipo de mapa de impuestos del tipo parametrizado tiene un código igual al valor GST mayor que 1.01.
  • {'$ o': [{'code': '10'}, {'skus': {'$ y': [{'price': {'$ in': ['20', '40']} }, {'código': 'RedApple'}]}}]}
    • Seleccione todos los productos donde el código de producto sea 10 o el precio de sku en 20 y 40 y el código de sku sea "RedApple".
Kamran Ali Khan
fuente
1
Debes negar que eres el autor (como creo que es el caso).
assylias 05 de
Sí, soy el autor de esta biblioteca.
Kamran Ali Khan
2

Escribí una clase Iterable extendida que admite la aplicación de algoritmos funcionales sin copiar el contenido de la colección.

Uso:

List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }

Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
    public Boolean call(Integer n) throws FunctionalException
    {
        return n % 2 == 0;
    }
})

for( int n : filtered )
{
    System.out.println(n);
}

El código anterior se ejecutará realmente

for( int n : myList )
{
    if( n % 2 == 0 ) 
    {
        System.out.println(n);
    }
}
Vincent Robert
fuente
2

Algunas respuestas realmente geniales aquí. A mí, me gustaría mantener las cosas tan simples y legibles como sea posible:

public abstract class AbstractFilter<T> {

    /**
     * Method that returns whether an item is to be included or not.
     * @param item an item from the given collection.
     * @return true if this item is to be included in the collection, false in case it has to be removed.
     */
    protected abstract boolean excludeItem(T item);

    public void filter(Collection<T> collection) {
        if (CollectionUtils.isNotEmpty(collection)) {
            Iterator<T> iterator = collection.iterator();
            while (iterator.hasNext()) {
                if (excludeItem(iterator.next())) {
                    iterator.remove();
                }
            }
        }
    }
}
Lawrence
fuente
Simplemente implemente el excludeItem apropiado por filtro. Terminará teniendo filtros separados exactamente como tiene clasificadores en Colecciones ...
Lawrence
1

La solución simple anterior a Java8:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

Desafortunadamente, esta solución no es completamente genérica, ya que genera una lista en lugar del tipo de la colección dada. Además, traer bibliotecas o escribir funciones que envuelvan este código me parece excesivo a menos que la condición sea compleja, pero luego puede escribir una función para la condición.

Andrew McKnight
fuente
1

https://code.google.com/p/joquery/

Admite diferentes posibilidades,

Dada la colección,

Collection<Dto> testList = new ArrayList<>();

de tipo,

class Dto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

Filtrar

Java 7

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property("id").eq().value(1);
Collection<Dto> filtered = query.list();

Java 8

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property(Dto::getId)
    .eq().value(1);
Collection<Dto> filtered = query.list();

También,

Filter<Dto> query = CQ.<Dto>filter()
        .from(testList)
        .where()
        .property(Dto::getId).between().value(1).value(2)
        .and()
        .property(Dto::grtText).in().value(new string[]{"a","b"});

Clasificación (también disponible para Java 7)

Filter<Dto> query = CQ.<Dto>filter(testList)
        .orderBy()
        .property(Dto::getId)
        .property(Dto::getName)
    Collection<Dto> sorted = query.list();

Agrupación (también disponible para Java 7)

GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
        .group()
        .groupBy(Dto::getId)
    Collection<Grouping<Integer,Dto>> grouped = query.list();

Uniones (también disponible para Java 7)

Dado,

class LeftDto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

class RightDto
{
    private int id;
    private int leftId;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getLeftId()
        {
            return leftId;
        }

    public int getText()
    {
        return text;
    }
}

class JoinedDto
{
    private int leftId;
    private int rightId;
    private String text;

    public JoinedDto(int leftId,int rightId,String text)
    {
        this.leftId = leftId;
        this.rightId = rightId;
        this.text = text;
    }

    public int getLeftId()
    {
        return leftId;
    }

    public int getRightId()
        {
            return rightId;
        }

    public int getText()
    {
        return text;
    }
}

Collection<LeftDto> leftList = new ArrayList<>();

Collection<RightDto> rightList = new ArrayList<>();

Se puede unir como,

Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
                .<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
                .on(LeftFyo::getId, RightDto::getLeftId)
                .transformDirect(selection ->  new JoinedDto(selection.getLeft().getText()
                                                     , selection.getLeft().getId()
                                                     , selection.getRight().getId())
                                 )
                .list();

Expresiones

Filter<Dto> query = CQ.<Dto>filter()
    .from(testList)
    .where()
    .exec(s -> s.getId() + 1).eq().value(2);
Pelican de bajo vuelo
fuente
1

Mi respuesta se basa en eso de Kevin Wong, aquí como una línea usando CollectionUtilsfrom spring y una expresión lambda de Java 8 .

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

Esto es tan conciso y legible como cualquier otra alternativa que haya visto (sin usar bibliotecas basadas en aspectos)

Spring CollectionUtils está disponible a partir de la versión 4.0.2.RELEASE de Spring, y recuerde que necesita JDK 1.8 y nivel de idioma 8+.

vikingsteve
fuente
1

Utilizando java 8, específicamente lambda expression, puede hacerlo simplemente como en el siguiente ejemplo:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

donde para cada colección productinterna myProducts, si prod.price>10, luego agregue este producto a la nueva lista filtrada.

hd84335
fuente
1

Necesitaba filtrar una lista dependiendo de los valores ya presentes en la lista. Por ejemplo, elimine todos los valores siguientes que sean menores que el valor actual. {2 5 3 4 7 5} -> {2 5 7}. O, por ejemplo, para eliminar todos los duplicados {3 5 4 2 3 5 6} -> {3 5 4 2 6}.

public class Filter {
    public static <T> void List(List<T> list, Chooser<T> chooser) {
        List<Integer> toBeRemoved = new ArrayList<>();
        leftloop:
        for (int right = 1; right < list.size(); ++right) {
            for (int left = 0; left < right; ++left) {
                if (toBeRemoved.contains(left)) {
                    continue;
                }
                Keep keep = chooser.choose(list.get(left), list.get(right));
                switch (keep) {
                    case LEFT:
                        toBeRemoved.add(right);
                        continue leftloop;
                    case RIGHT:
                        toBeRemoved.add(left);
                        break;
                    case NONE:
                        toBeRemoved.add(left);
                        toBeRemoved.add(right);
                        continue leftloop;
                }
            }
        }

        Collections.sort(toBeRemoved, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int i : toBeRemoved) {
            if (i >= 0 && i < list.size()) {
                list.remove(i);
            }
        }
    }

    public static <T> void List(List<T> list, Keeper<T> keeper) {
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (!keeper.keep(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public interface Keeper<E> {
        boolean keep(E obj);
    }

    public interface Chooser<E> {
        Keep choose(E left, E right);
    }

    public enum Keep {
        LEFT, RIGHT, BOTH, NONE;
    }
}

Esto se utilizará así.

List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
    @Override
    public Filter.Keep choose(String left, String right) {
        return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
    }
});
Fredrik Metcalf
fuente
0

Con guayaba:

Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);

Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
    @Override
    public boolean apply(Integer i) {
        return i % 2 == 0;
    }
});

System.out.println(collection); // Prints 1, 3, 5
ZhekaKozlov
fuente
0

En Java 8, puede usar directamente este método de filtro y luego hacerlo.

 List<String> lines = Arrays.asList("java", "pramod", "example");

 List<String> result = lines.stream()              
         .filter(line -> !"pramod".equals(line))     
         .collect(Collectors.toList());              

 result.forEach(System.out::println); 
pramod_m
fuente