Lista de Java.contiene (Objeto con valor de campo igual a x)
Quiero comprobar si un List
contiene un objeto que tiene un campo con un valor determinado. Ahora, podría usar un bucle para ir a través y comprobar, pero tenía curiosidad si había algo más eficiente código.
Algo como;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
Sé que el código anterior no hace nada, es solo para demostrar aproximadamente lo que estoy tratando de lograr.
También, solo para aclarar, la razón por la que no quiero usar un bucle simple es porque este código irá actualmente dentro de un bucle que está dentro de un bucle que está dentro de un bucle. Para la legibilidad no quiero seguir añadiendo bucles a estos bucles. Así que me pregunté si había alguna alternativa simple(ish).
12 answers
Flujos
Si está utilizando Java 8, tal vez podría intentar algo como esto:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}
O alternativamente, podrías intentar algo como esto:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}
Este método devolverá true
si el List<MyObject>
contiene un MyObject
con el nombre name
. Si desea realizar una operación en cada uno de los MyObject
s que getName().equals(name)
, entonces podría intentar algo como esto:
public void perform(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).forEach(
o -> {
//...
}
);
}
Donde o
representa una instancia MyObject
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-19 02:35:14
Tienes dos opciones.
1. La primera opción, que es preferible, es anular el método` equals () ' en su clase de objeto.
Digamos, por ejemplo, que tienes esta clase de objeto:
public class MyObject {
private String name;
private String location;
//getters and setters
}
Ahora digamos que solo le importa el nombre del miObjeto, que debe ser único, por lo que si dos `miObjeto ' tienen el mismo nombre deberían considerarse iguales. En ese caso, querrás anular el método` equals () ' (y también el método` hashcode ()') para que compara los nombres para determinar la igualdad.
Una vez hecho esto, puedes comprobar si una Colección contiene un myObject con el nombre "foo" de la siguiente manera:
MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
Sin embargo, esto podría no ser una opción para usted si:
- Está utilizando tanto el nombre como la ubicación para verificar la igualdad, pero solo desea verificar si una Colección tiene algún `myObject ' con una ubicación determinada. En este caso, ya has anulado `equals()`.
- 'myObject' es parte de una API que no tienes libertad para cambiar.
Si cualquiera de estos es el caso, usted querrá opción 2:
2. Escriba su propio método de utilidad:
public static boolean containsLocation(Collection<MyObject> c, String location) {
for(MyObject o : c) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Alternativamente, puede extender ArrayList (o alguna otra colección) y luego agregar su propio método:
public boolean containsLocation(String location) {
for(MyObject o : this) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Desafortunadamente no hay una mejor manera de evitarlo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-17 15:20:16
Google Guayaba
Si está utilizando Guayaba , puede tomar un enfoque funcional y hacer lo siguiente
FluentIterable.from(list).find(new Predicate<MyObject>() {
public boolean apply(MyObject input) {
return "John".equals(input.getName());
}
}).Any();
Que parece un poco prolijo. Sin embargo, el predicado es un objeto y puede proporcionar diferentes variantes para diferentes búsquedas. Observe cómo la propia biblioteca separa la iteración de la colección y la función que desea aplicar. No tienes que anular equals()
para un comportamiento en particular.
Como se indica a continuación, el java.útil.Stream framework integrado en Java 8 y posteriores proporciona algo similar.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-19 02:40:11
Búsqueda binaria
Puede usar Colecciones.binarySearch para buscar un elemento en su lista (suponiendo que la lista esté ordenada):
Collections.binarySearch(list, new YourObject("a1", "b",
"c"), new Comparator<YourObject>() {
@Override
public int compare(YourObject o1, YourObject o2) {
return o1.getName().compareTo(o2.getName());
}
});
Que devolverá un número negativo si el objeto no está presente en la colección o bien devolverá el index
del objeto. Con esto puedes buscar objetos con diferentes estrategias de búsqueda.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-19 02:33:19
Collection.contains()
se implementa llamando a equals()
en cada objeto hasta que uno devuelve true
.
Así que una forma de implementar esto es anular equals()
pero por supuesto, solo se puede tener uno igual.
Frameworks como Guava por lo tanto usan predicados para esto. Con Iterables.find(list, predicate)
, puede buscar campos arbitrarios poniendo la prueba en el predicado.
Otros lenguajes construidos encima de la VM tienen esto incorporado. En Groovy, por ejemplo, simplemente escribe:
def result = list.find{ it.name == 'John' }
Java 8 hizo todas nuestras vidas más fáciles, también:
List<Foo> result = list.stream()
.filter(it -> "John".equals(it.getName())
.collect(Collectors.toList());
Si te importan cosas como esta, te sugiero el libro "Beyond Java". Contiene muchos ejemplos de las numerosas deficiencias de Java y cómo otros lenguajes hacen mejor.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-08 13:16:28
Colecciones de eclipses
Si estás usando Colecciones de eclipse, puedes usar el método anySatisfy()
. Puede adaptar su List
en un ListAdapter
o cambiar su List
en un ListIterable
si es posible.
ListIterable<MyObject> list = ...;
boolean result =
list.anySatisfy(myObject -> myObject.getName().equals("John"));
Si va a hacer operaciones como esta con frecuencia, es mejor extraer un método que responda si el tipo tiene el atributo.
public class MyObject
{
private final String name;
public MyObject(String name)
{
this.name = name;
}
public boolean named(String name)
{
return Objects.equals(this.name, name);
}
}
Puede utilizar la forma alternativa anySatisfyWith()
junto con una referencia de método.
boolean result = list.anySatisfyWith(MyObject::named, "John");
Si no puede cambiar su List
en a ListIterable
, así es como usarías ListAdapter
.
boolean result =
ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
Nota: Soy un committer para ollections de Eclipse.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-19 12:58:56
Mapa
Puede crear un Hashmap<String, Object>
usando uno de los valores como clave, y luego ver si yourHashMap.keySet().contains(yourValue)
devuelve true.
Predicate
Si no utiliza Java 8, o biblioteca que le da más funcionalidad para tratar con colecciones, podría implementar algo que puede ser más reutilizable que su solución.
interface Predicate<T>{
boolean contains(T item);
}
static class CollectionUtil{
public static <T> T find(final Collection<T> collection,final Predicate<T> predicate){
for (T item : collection){
if (predicate.contains(item)){
return item;
}
}
return null;
}
// and many more methods to deal with collection
}
Estoy usando algo así, tengo interfaz de predicado, y estoy pasando la implementación a mi clase util.
¿Cuál es la ventaja de hacer esto a mi manera? usted tiene un método que se ocupa de la búsqueda en cualquier tipo de colección. y no tienes que crear separado métodos si desea buscar por campo diferente. todo lo que hay que hacer es proporcionar predicado diferente que puede ser destruido tan pronto como ya no es útil /
Si desea usarlo, todo lo que necesita hacer es llamar al método y definir su predicado
CollectionUtil.find(list, new Predicate<MyObject>{
public boolean contains(T item){
return "John".equals(item.getName());
}
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-19 02:32:43
contains
el método utiliza equals
internamente. Por lo tanto, necesita anular el método equals
para su clase según su necesidad.
Por cierto esto no parece sintáticamente correcto:
new Object().setName("John")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-17 14:06:27
Si necesita realizar esto List.contains(Object with field value equal to x)
repetidamente, una solución simple y eficiente sería:
List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
fieldOfInterestValues.add(obj.getFieldOfInterest());
}
Entonces el List.contains(Object with field value equal to x)
tendría el mismo resultado que fieldOfInterestValues.contains(x);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-16 12:24:15
A pesar de JAVA 8 SDK hay una gran cantidad de bibliotecas de herramientas de colección que pueden ayudarlo a trabajar, por ejemplo: http://commons.apache.org/proper/commons-collections /
Predicate condition = new Predicate() {
boolean evaluate(Object obj) {
return ((Sample)obj).myField.equals("myVal");
}
};
List result = CollectionUtils.select( list, condition );
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-22 05:34:27
Aquí hay una solución usando Guayaba
private boolean checkUserListContainName(List<User> userList, final String targetName){
return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
@Override
public boolean apply(@Nullable User input) {
return input.getName().equals(targetName);
}
});
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-21 02:55:33