¿Cómo obtener una lista de valores de campos específicos de objetos almacenados en una lista?

8 minutos de lectura

avatar de usuario de user1343585
usuario1343585

Digamos que tengo una lista de objetos con dos campos field1 y field2ambos de tipo String.

¿Cómo obtengo una lista de todos field1 valores sin tener que iterar sobre la lista, si es posible?

  • No, no lo hay, en el caso común. O tienes mas detalles?

    – kan

    12 de junio de 2012 a las 12:59


  • “sin tener que iterar”, en absoluto, supongo.

    – Umesh Aawte

    12/06/2012 a las 13:00

  • without having to iterate through the list ¿Quiere decir que no iteraría a través de la lista, o incluso una biblioteca no lo haría? Básicamente, ¿solo quiere algo fácil de escribir, o realmente acceso O (1) a un subconjunto de objetos según las condiciones? Son 2 preguntas completamente diferentes.

    – Haylem

    12 de junio de 2012 a las 13:13

Afortunadamente, puedes hacer esto usando Java 8 – Flujos

Suponga que tiene una entidad llamada TuEntidad

public class YourEntity {

    private String field1;
    private String field2;

    public YourEntity(String field1, String field2) {
        this.field1 = field1;
        this.field2 = field2;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public void setField2(String field2) {
        this.field2 = field2;
    }

    public String getField1() {
        return field1;
    }

    public String getField2() {
        return field2;
    }
}

Declara tu lista de TuEntidad usando:

List<YourEntity> entities = Arrays.asList(new YourEntity("text1", "text2"), new YourEntity("text3", "text4"));

Puede extraer la lista de campo1 de una sola vez de esta manera:

import java.util.stream.Collectors;

List<String> field1List = entities.stream().map(YourEntity::getField1).collect(Collectors.toList());

O de esta manera

import java.util.stream.Collectors;

List<String> field1List = entities.stream().map(urEntity -> urEntity.getField1()).collect(Collectors.toList());

Puede imprimir todos los artículos también usando Java 8 🙂

field1List.forEach(System.out::println);

Producción

text1
text3

  • ¿Cómo se puede lograr esto para cualquier número de campos en una clase de entidad? Digamos que estoy escribiendo un método común para lograr esto en cualquier cantidad de campos en una sola clase de entidad o cualquier clase de entidad que envíe como argumento en el método.

    – Harshit

    20 de julio de 2018 a las 8:59

Avatar de usuario de Euclides Mulémbwè
Euclides Mulemwè

prueba esto:

List<Entity> entities = getEntities();
List<Integer> listIntegerEntities = Lambda.extract(entities, Lambda.on(Entity.class).getFielf1());

LambdaJ permite acceder a colecciones sin bucles explícitos, por lo que en lugar de tener más líneas de código para iterar la lista usted mismo, deje que LambdaJ lo haga.

  • Esta respuesta definitivamente debería actualizarse con una breve descripción de lo que se usa aquí (¿LambdaJ?)

    – toniedzwiedz

    12 de junio de 2012 a las 13:04


Un objeto es una referencia hacia una dirección de memoria. Entonces, los campos de estos objetos son otras referencias hacia otras direcciones de memoria. Por lo tanto, una lista de objetos es una lista de referencias. Por lo tanto, es imposible que la lista acceda directamente a los campos del objeto (referencias dadas por las referencias). La respuesta corta es no.

Nota: de todos modos, encontrará una API que hace lo que quiere, aún se repite en el interior.

  • Tenga en cuenta necesariamente. Podría implementar una colección que, al insertarla, agregue elementos a una lista, que indexe en función de los criterios de búsqueda, y luego devuelva la lista directamente. De esta manera, la inserción sería algo ineficiente, pero la recuperación permitiría hacer lo que quiere el OP.

    – Haylem

    12 de junio de 2012 a las 13:19


  • Eso es cierto, pero dicha colección sería muy específica para el tipo de objetos que contiene, en lugar de ser genérica.

    – dounyy

    12 de junio de 2012 a las 13:25

  • en parte, sí, para no hacer que sea completamente “fijo”, necesitaría usar interfaces de límite o reflexión, por lo que debe imponer una ligera rigidez a los tipos que puede insertar, o un impacto en el rendimiento y la complejidad del indexador. Pero eso es perfectamente factible, sin embargo. De hecho, no me sorprendería si algunas de las bibliotecas y extensiones de lenguaje que se han implementado para proporcionar capacidades de consulta a las colecciones de Java y los objetos compuestos estuvieran usando algo similar al segundo enfoque.

    – Haylem

    12 de junio de 2012 a las 14:25

  • No estoy de acuerdo aquí; es cierto que, lógicamente, una lista debe ser la lista de referencias, pero una lista es solo una interfaz: si devuelve lo correcto, no es necesario que tenga una tienda de respaldo. Vea mi respuesta a continuación para una versión que no se repite y cumple con los requisitos.

    – usuario295691

    21/01/2014 a las 21:55

avatar de usuario de haylem
Haylem

Depende…

… si sus preguntas se refieren a avoiding iterating over the collection cualquiera:

  • en términos de facilidad de implementación en puntos de llamada
  • o en términos de la complejidad algorítmica.

Concretamente, quiere decir:

  • no desea escribir una construcción iterativa usted mismo (simplemente use una biblioteca de conveniencia),
  • o realmente quiere algo que devuelva elementos automáticamente en O (1) sin necesidad de procesarlos (y tener acceso perfecto)?

Vea a continuación las soluciones y opciones.


Uso de bibliotecas de conveniencia

Si es el primero, busque Google Guava, LambdaJ, FunctionalJava u otras bibliotecas que implementen construcciones funcionales básicas y le permitirán hacer lo que quiera en unas pocas llamadas expresivas. Pero tenga en cuenta que estos hacen lo que dice en la lata: filtrarán, recopilarán o transformarán una colección, e iterarán a través de sus elementos para hacer esto.

Por ejemplo:

  • Google guayaba:

    Set<String> strings = buildSetStrings();  
    Collection<String> filteredStrings =
        Collections2.filter(strings, Predicates.containsPattern("^J"));  
    
  • Java funcional:

    Array<Integer> a = array(97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42);
    Array<Integer> b = a.filter(even);
    
  • LambdaJ:

    List<Integer> biggerThan3 = filter(greaterThan(3), asList(1, 2, 3, 4, 5));
    

Acceso perfecto

Si es el segundo, esto no es posible tal cual, excepto si diseñaras todo desde el principio para que sus objetos deben ser administrados por una clase de colección personalizada que indexaría sus objetos en función de sus valores de campo en la inserción.

Los mantendría en cubos indexados por dicho valor para que estén fácilmente disponibles para que los recupere como una lista o conjunto a pedido.

Como se menciona en los comentarios debajo de la respuesta de dounyy, el diseño de una colección personalizada de este tipo probablemente tendría un impacto en la API de los elementos que aceptaría (muy probablemente al definir una superinterfaz para usar con los tipos de elementos), o requeriría una implementación bastante compleja. para resolver los miembros dinámicamente (muy probablemente mediante el uso de la reflexión), si alguna vez quiso que esta colección fuera genérica.

Ni Java como lenguaje ni las bibliotecas JDK aún no hacen lo que quieres. Puedes usar LambdaJ o espere a Java 8 que se espera que incluya expresiones lambda.

  • ¿Cómo evitaría eso la iteración? Lambda J todavía lo haría por ti. de lo contrario, ya podría usar Google Guava para eso, o LambdaJ, o FunctionalJava, o muchos otros. Pero todos iteran a través de las estructuras, por supuesto.

    – Haylem

    12 de junio de 2012 a las 13:04


  • Tienes razón, @haylem. Obviamente, alguien debe iterar sobre la colección. No hay forma de evitarlo. Cuando los cierres se introduzcan en Java, harán lo mismo detrás de escena. Las herramientas que mencionó solo nos ayudan a escribir código más corto.

    – AlexR

    13 de junio de 2012 a las 6:21

avatar de usuario de user295691
usuario295691

Pregunta antigua, pero me encontré con ella mientras buscaba para ver si podía mejorar una solución similar.

Puede implementar el List<String> interfaz sin crear un desarrollado ArrayList<String>y por lo tanto no itera sobre el objeto principal.

final List<Entity> entities = getEntities()
final List<String> field1 = new AbstractList() {
    public String get(int index) {
        return entities.get(index).getField1();
    }
    public int size() {
        return entities.size();
    }
}

Eso le da una Lista sin iterar sobre el objeto principal.

Acceso aleatorio a la derivada List<String> será tan costoso como el acceso aleatorio al subyacente List<Entity>; si está utilizando una implementación de List<Entity> que no proporciona un acceso aleatorio rápido, es posible que deba pasar por un par de aros (es decir, implementar más métodos de List<String>. Pero esto debería funcionar en el 99 % de los casos en los que necesite un adaptador ligero.

  • ¿Cómo evitaría eso la iteración? Lambda J todavía lo haría por ti. de lo contrario, ya podría usar Google Guava para eso, o LambdaJ, o FunctionalJava, o muchos otros. Pero todos iteran a través de las estructuras, por supuesto.

    – Haylem

    12 de junio de 2012 a las 13:04


  • Tienes razón, @haylem. Obviamente, alguien debe iterar sobre la colección. No hay forma de evitarlo. Cuando los cierres se introduzcan en Java, harán lo mismo detrás de escena. Las herramientas que mencionó solo nos ayudan a escribir código más corto.

    – AlexR

    13 de junio de 2012 a las 6:21

Avatar de usuario de manasBVSS
manasbvss

Sea el objeto de la siguiente clase.

public class Bike {

    String bikeModel;
    Int price;
}

Y ahora hay una lista de bicicletas llamada bikeList de tipo List

Así que ahora queremos una lista de modelos de bicicletas de todas las bicicletas en la lista anterior.

bikeList.map{ Bike b -> b.bikeModel }.toCollection(arrayListOf())

devuelve una lista de matriz del primer campo de todos los objetos de bicicleta en bikeList

¿Ha sido útil esta solución?