Agrupar una lista de objetos por un atributo: Java


97

Necesito agrupar una lista de objetos (Estudiante) usando un atributo (Ubicación) del objeto en particular, el código es el siguiente,

public class Grouping {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        List<Student> studlist = new ArrayList<Student>();
        studlist.add(new Student("1726", "John", "New York"));
        studlist.add(new Student("4321", "Max", "California"));
        studlist.add(new Student("2234", "Andrew", "Los Angeles"));
        studlist.add(new Student("5223", "Michael", "New York"));
        studlist.add(new Student("7765", "Sam", "California"));
        studlist.add(new Student("3442", "Mark", "New York"));

        //Code to group students by location
        /*  Output should be Like below
            ID : 1726   Name : John Location : New York
            ID : 5223   Name : Michael  Location : New York
            ID : 4321   Name : Max  Location : California
            ID : 7765   Name : Sam  Location : California    

         */

        for (Student student : studlist) {
            System.out.println("ID : "+student.stud_id+"\t"+"Name : "+student.stud_name+"\t"+"Location : "+student.stud_location);
        }


    }
}

class Student {

    String stud_id;
    String stud_name;
    String stud_location;

    Student(String sid, String sname, String slocation) {

        this.stud_id = sid;
        this.stud_name = sname;
        this.stud_location = slocation;

    }
}

Sugiéreme una forma limpia de hacerlo.


2
Un mapa hash con la ubicación como clave y la lista de estudiantes como valor.
Omoro

¿La clasificación por ubicación resolvería su problema o hay algo más?
Warlord

Intente usar Comparator y ordene por ubicación.
pshemek

1
@Warlord Sí, pero ir más lejos si necesito obtener información como, Mejor conteo de estudiantes por ubicación si pudiera agruparlo
Dilukshan Mahendra

@Omoro Por favor, ¿puede darme una pista por código? No estoy tan familiarizado con Hashmaps
Dilukshan Mahendra

Respuestas:


131

Esto agregará el objeto de los estudiantes a la clave HashMapwith locationIDas.

HashMap<Integer, List<Student>> hashMap = new HashMap<Integer, List<Student>>();

Repita este código y agregue estudiantes a HashMap:

if (!hashMap.containsKey(locationId)) {
    List<Student> list = new ArrayList<Student>();
    list.add(student);

    hashMap.put(locationId, list);
} else {
    hashMap.get(locationId).add(student);
}

Si desea que todos los estudiantes tengan detalles de ubicación particulares, puede usar esto:

hashMap.get(locationId);

que le dará a todos los estudiantes con el mismo ID de ubicación.


4
Declaró una Lista de objetos de ubicación y en la siguiente línea agrega un objeto Estudiante a la lista anterior que debería arrojar un error.
OJVM

hashMap.get () devuelve nulo cuando hashMap.contanisKey () devuelve falso. Puede guardar la llamada al método containsKey () si llama primero a hashMap.get (), almacena el resultado en una var local y verifica si esta var local es nula
Esteve

250

En Java 8:

Map<String, List<Student>> studlistGrouped =
    studlist.stream().collect(Collectors.groupingBy(w -> w.stud_location));

Eso es porque en Studentclase stud_locationse especifica como Amistoso. Solo puede acceder la Studentclase y cualquier clase que esté definida en el mismo paquete de . Si pones en lugar de , esto debería funcionar. O puede definir una función getter. Más información en cs.princeton.edu/courses/archive/spr96/cs333/java/tutorial/java/…Studentstud_locationpublic String stud_location;String stud_location;
Eranga Heshan

32
Map<String, List<Student>> map = new HashMap<String, List<Student>>();

for (Student student : studlist) {
    String key  = student.stud_location;
    if(map.containsKey(key)){
        List<Student> list = map.get(key);
        list.add(student);

    }else{
        List<Student> list = new ArrayList<Student>();
        list.add(student);
        map.put(key, list);
    }

}

8

Usando Java 8

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class Student {

    String stud_id;
    String stud_name;
    String stud_location;

    public String getStud_id() {
        return stud_id;
    }

    public String getStud_name() {
        return stud_name;
    }

    public String getStud_location() {
        return stud_location;
    }



    Student(String sid, String sname, String slocation) {

        this.stud_id = sid;
        this.stud_name = sname;
        this.stud_location = slocation;

    }
}

class Temp
{
    public static void main(String args[])
    {

        Stream<Student> studs = 
        Stream.of(new Student("1726", "John", "New York"),
                new Student("4321", "Max", "California"),
                new Student("2234", "Max", "Los Angeles"),
                new Student("7765", "Sam", "California"));
        Map<String, Map<Object, List<Student>>> map= studs.collect(Collectors.groupingBy(Student::getStud_name,Collectors.groupingBy(Student::getStud_location)));
                System.out.println(map);//print by name and then location
    }

}

El resultado será:

{
    Max={
        Los Angeles=[Student@214c265e], 
        California=[Student@448139f0]
    }, 
    John={
        New York=[Student@7cca494b]
    }, 
    Sam={
        California=[Student@7ba4f24f]
    }
}

Esta respuesta se puede mejorar si se sigue el mismo ejemplo que la pregunta. Además, el resultado no coincide con el resultado deseado solicitado en la pregunta.
Pim Hazebroek

5

Agrupación de Java 8 por colector

Probablemente sea tarde, pero me gusta compartir una idea mejorada sobre este problema. Esta es básicamente la misma respuesta de @Vitalii Fedorenko, pero es más fácil de jugar.

Puede usar simplemente Collectors.groupingBy()pasando la lógica de agrupación como parámetro de función y obtendrá la lista dividida con la asignación de parámetros clave. Tenga en cuenta que el uso Optionalse utiliza para evitar la NPE no deseada cuando la lista proporcionada esnull

public static <E, K> Map<K, List<E>> groupBy(List<E> list, Function<E, K> keyFunction) {
    return Optional.ofNullable(list)
            .orElseGet(ArrayList::new)
            .stream()
            .collect(Collectors.groupingBy(keyFunction));
}

Ahora puede agrupar por cualquier cosa con esto. Para el caso de uso aquí en la pregunta

Map<String, List<Student>> map = groupBy(studlist, Student::getLocation);

Tal vez le gustaría consultar también esta Guía para la agrupación de Java 8By Collector


4

Puede utilizar lo siguiente:

Map<String, List<Student>> groupedStudents = new HashMap<String, List<Student>>();
for (Student student: studlist) {
    String key = student.stud_location;
    if (groupedStudents.get(key) == null) {
        groupedStudents.put(key, new ArrayList<Student>());
    }
    groupedStudents.get(key).add(student);
}

//impresión

Set<String> groupedStudentsKeySet = groupedCustomer.keySet();
for (String location: groupedStudentsKeySet) {
   List<Student> stdnts = groupedStudents.get(location);
   for (Student student : stdnts) {
        System.out.println("ID : "+student.stud_id+"\t"+"Name : "+student.stud_name+"\t"+"Location : "+student.stud_location);
    }
}

4

Implemente SQL GROUP BY Feature en Java usando Comparator, comparator comparará los datos de su columna y los ordenará. Básicamente, si mantiene los datos ordenados que se ven como datos agrupados, por ejemplo, si tiene los mismos datos de columna repetidos, el mecanismo de clasificación los clasifica manteniendo los mismos datos en un lado y luego busca otros datos que sean datos diferentes. Esto se ve indirectamente como AGRUPACIÓN de los mismos datos.

public class GroupByFeatureInJava {

    public static void main(String[] args) {
        ProductBean p1 = new ProductBean("P1", 20, new Date());
        ProductBean p2 = new ProductBean("P1", 30, new Date());
        ProductBean p3 = new ProductBean("P2", 20, new Date());
        ProductBean p4 = new ProductBean("P1", 20, new Date());
        ProductBean p5 = new ProductBean("P3", 60, new Date());
        ProductBean p6 = new ProductBean("P1", 20, new Date());

        List<ProductBean> list = new ArrayList<ProductBean>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        list.add(p5);
        list.add(p6);

        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            ProductBean bean = (ProductBean) iterator.next();
            System.out.println(bean);
        }
        System.out.println("******** AFTER GROUP BY PRODUCT_ID ******");
        Collections.sort(list, new ProductBean().new CompareByProductID());
        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            ProductBean bean = (ProductBean) iterator.next();
            System.out.println(bean);
        }

        System.out.println("******** AFTER GROUP BY PRICE ******");
        Collections.sort(list, new ProductBean().new CompareByProductPrice());
        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            ProductBean bean = (ProductBean) iterator.next();
            System.out.println(bean);
        }
    }
}

class ProductBean {
    String productId;
    int price;
    Date date;

    @Override
    public String toString() {
        return "ProductBean [" + productId + " " + price + " " + date + "]";
    }
    ProductBean() {
    }
    ProductBean(String productId, int price, Date date) {
        this.productId = productId;
        this.price = price;
        this.date = date;
    }
    class CompareByProductID implements Comparator<ProductBean> {
        public int compare(ProductBean p1, ProductBean p2) {
            if (p1.productId.compareTo(p2.productId) > 0) {
                return 1;
            }
            if (p1.productId.compareTo(p2.productId) < 0) {
                return -1;
            }
            // at this point all a.b,c,d are equal... so return "equal"
            return 0;
        }
        @Override
        public boolean equals(Object obj) {
            // TODO Auto-generated method stub
            return super.equals(obj);
        }
    }

    class CompareByProductPrice implements Comparator<ProductBean> {
        @Override
        public int compare(ProductBean p1, ProductBean p2) {
            // this mean the first column is tied in thee two rows
            if (p1.price > p2.price) {
                return 1;
            }
            if (p1.price < p2.price) {
                return -1;
            }
            return 0;
        }
        public boolean equals(Object obj) {
            // TODO Auto-generated method stub
            return super.equals(obj);
        }
    }

    class CompareByCreateDate implements Comparator<ProductBean> {
        @Override
        public int compare(ProductBean p1, ProductBean p2) {
            if (p1.date.after(p2.date)) {
                return 1;
            }
            if (p1.date.before(p2.date)) {
                return -1;
            }
            return 0;
        }
        @Override
        public boolean equals(Object obj) {
            // TODO Auto-generated method stub
            return super.equals(obj);
        }
    }
}

La salida está aquí para la lista de ProductBean anterior se hace con los criterios de GROUP BY, aquí si ve los datos de entrada que se le da la lista de ProductBean a Collections.sort (lista, objeto de Comparator para su columna requerida) Esto se ordenará según la implementación de su comparador y podrá ver los datos AGRUPADOS en la siguiente salida. Espero que esto ayude...

    ******** ANTES DE AGRUPAR LOS DATOS DE ENTRADA SE VE DE ESTA MANERA ******
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 30 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P2 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P3 60 Lunes 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ******** DESPUÉS DE AGRUPAR POR PRODUCT_ID ******
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 30 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P2 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P3 60 Lunes 17 de noviembre 09:31:01 IST 2014]

    ******** DESPUÉS DE GRUPO POR PRECIO ******
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P2 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 20 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P1 30 lun 17 de noviembre 09:31:01 IST 2014]
    ProductBean [P3 60 Lunes 17 de noviembre 09:31:01 IST 2014]


1
Hola, no publique la misma respuesta varias veces y no publique código sin formato sin una explicación sobre cómo funciona y cómo resuelve el problema en la pregunta anterior.
Mat

Lo siento amigo, hubo un error al pegar el código, ya que podría haberse vuelto varias veces. He editado la explicación de lo que publiqué. Espero que se vea bien ahora ???
Ravi Beli

Me falta algo o este código está ordenando en lugar de agrupar por un campo. Veo productos ordenados por ID, luego por Precio
Financiador

0

Puedes ordenar así:

    Collections.sort(studlist, new Comparator<Student>() {

        @Override
        public int compare(Student o1, Student o2) {
            return o1.getStud_location().compareTo(o2.getStud_location());
        }
    });

Suponiendo que también tenga el captador de ubicación en su clase de Estudiante.


3
¿Por qué ordenar? ¡El problema es agrupar los elementos!
Sankalp

0

Podrías hacer esto:

Map<String, List<Student>> map = new HashMap<String, List<Student>>();
List<Student> studlist = new ArrayList<Student>();
studlist.add(new Student("1726", "John", "New York"));
map.put("New York", studlist);

las claves serán las ubicaciones y la lista de valores de los estudiantes. Entonces, más tarde, puede obtener un grupo de estudiantes simplemente usando:

studlist = map.get("New York");

0

puedes usar guava'sMultimaps

@Canonical
class Persion {
     String name
     Integer age
}
List<Persion> list = [
   new Persion("qianzi", 100),
   new Persion("qianzi", 99),
   new Persion("zhijia", 99)
]
println Multimaps.index(list, { Persion p -> return p.name })

imprime:

[qianzi: [com.ctcf.message.Persion (qianzi, 100), com.ctcf.message.Persion (qianzi, 88)], zhijia: [com.ctcf.message.Persion (zhijia, 99)]]


0
Function<Student, List<Object>> compositKey = std ->
                Arrays.asList(std.stud_location());
        studentList.stream().collect(Collectors.groupingBy(compositKey, Collectors.toList()));

Si desea agregar varios objetos para agrupar, simplemente puede agregar el objeto en el compositKeymétodo separándolo por una coma:

Function<Student, List<Object>> compositKey = std ->
                Arrays.asList(std.stud_location(),std.stud_name());
        studentList.stream().collect(Collectors.groupingBy(compositKey, Collectors.toList()));

0
public class Test9 {

    static class Student {

        String stud_id;
        String stud_name;
        String stud_location;

        public Student(String stud_id, String stud_name, String stud_location) {
            super();
            this.stud_id = stud_id;
            this.stud_name = stud_name;
            this.stud_location = stud_location;
        }

        public String getStud_id() {
            return stud_id;
        }

        public void setStud_id(String stud_id) {
            this.stud_id = stud_id;
        }

        public String getStud_name() {
            return stud_name;
        }

        public void setStud_name(String stud_name) {
            this.stud_name = stud_name;
        }

        public String getStud_location() {
            return stud_location;
        }

        public void setStud_location(String stud_location) {
            this.stud_location = stud_location;
        }

        @Override
        public String toString() {
            return " [stud_id=" + stud_id + ", stud_name=" + stud_name + "]";
        }

    }

    public static void main(String[] args) {

        List<Student> list = new ArrayList<Student>();
        list.add(new Student("1726", "John Easton", "Lancaster"));
        list.add(new Student("4321", "Max Carrados", "London"));
        list.add(new Student("2234", "Andrew Lewis", "Lancaster"));
        list.add(new Student("5223", "Michael Benson", "Leeds"));
        list.add(new Student("5225", "Sanath Jayasuriya", "Leeds"));
        list.add(new Student("7765", "Samuael Vatican", "California"));
        list.add(new Student("3442", "Mark Farley", "Ladykirk"));
        list.add(new Student("3443", "Alex Stuart", "Ladykirk"));
        list.add(new Student("4321", "Michael Stuart", "California"));

        Map<String, List<Student>> map1  =

                list
                .stream()

            .sorted(Comparator.comparing(Student::getStud_id)
                    .thenComparing(Student::getStud_name)
                    .thenComparing(Student::getStud_location)
                    )

                .collect(Collectors.groupingBy(

                ch -> ch.stud_location

        ));

        System.out.println(map1);

/*
  Output :

{Ladykirk=[ [stud_id=3442, stud_name=Mark Farley], 
 [stud_id=3443, stud_name=Alex Stuart]], 

 Leeds=[ [stud_id=5223, stud_name=Michael Benson],  
 [stud_id=5225, stud_name=Sanath Jayasuriya]],


  London=[ [stud_id=4321, stud_name=Max Carrados]],


   Lancaster=[ [stud_id=1726, stud_name=John Easton],  

   [stud_id=2234, stud_name=Andrew Lewis]], 


   California=[ [stud_id=4321, stud_name=Michael Stuart],  
   [stud_id=7765, stud_name=Samuael Vatican]]}
*/


    }// main
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.