Agrupe uma lista de objetos por um atributo: Java

97

Preciso agrupar uma lista de objetos (Aluno) usando um atributo (Localização) do objeto em particular, o código é como abaixo,

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;

    }
}

Por favor, me sugira uma maneira limpa de fazer isso.

Dilukshan Mahendra
fonte
2
Um hashmap com a localização como chave e a lista dos alunos como valor.
Omoro de
A classificação por local resolveria seu problema ou há outra coisa?
Warlord de
Tente usar o Comparator e classifique por local.
pshemek de
1
@Warlord Sim, mas vou mais longe se precisar de informações como, contagem de alunos por local melhor se pudesse agrupá-la
Dilukshan Mahendra
@Omoro Por favor, você pode me dar uma pista por código, Não estou tão familiarizado com Hashmaps
Dilukshan Mahendra

Respostas:

130

Isto irá adicionar o objeto estudantes ao HashMapcom locationIDcomo chave.

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

Repita este código e adicione alunos ao HashMap:

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

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

Se quiser todos os alunos com detalhes de localização específicos, você pode usar isto:

hashMap.get(locationId);

o que levará você a todos os alunos com a mesma identificação de local.

Dileep
fonte
4
Você declarou uma Lista de objetos de Localização e, na próxima linha, adiciona um objeto de Aluno à lista anterior que deve gerar um erro.
OJVM
hashMap.get () retorna nulo quando hashMap.contanisKey () retorna falso. Você poderia salvar a chamada para o método containsKey () se chamar primeiro hashMap.get (), armazenar o resultado em um var local e verificar se este var local é nulo
Esteve
247

Em Java 8:

Map<String, List<Student>> studlistGrouped =
    studlist.stream().collect(Collectors.groupingBy(w -> w.stud_location));
Vitalii Fedorenko
fonte
Isso ocorre porque em Studentclasse stud_locationé especificado como Amigável. Apenas a Studentclasse e qualquer classe definida no mesmo pacote de Studentpode acessar stud_location. Se você colocar em public String stud_location;vez de String stud_location;, isso deve funcionar. Ou você pode definir uma função getter. Mais informações em cs.princeton.edu/courses/archive/spr96/cs333/java/tutorial/java/…
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);
    }

}
Sampath Challa
fonte
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
    }

}

O resultado será:

{
    Max={
        Los Angeles=[Student@214c265e], 
        California=[Student@448139f0]
    }, 
    John={
        New York=[Student@7cca494b]
    }, 
    Sam={
        California=[Student@7ba4f24f]
    }
}
Chirag
fonte
Essa resposta pode ser melhorada seguindo o mesmo exemplo da pergunta. Além disso, o resultado não corresponde à saída desejada solicitada na pergunta.
Pim Hazebroek
5

Java 8 groupingBy Collector

Provavelmente é tarde, mas gosto de compartilhar uma ideia melhorada para este problema. Esta é basicamente a mesma resposta de @Vitalii Fedorenko, mas é mais fácil de brincar.

Você pode apenas usar o Collectors.groupingBy()passando a lógica de agrupamento como parâmetro de função e você obterá a lista dividida com o mapeamento de parâmetro-chave. Observe que o uso Optionalé usado para evitar o NPE indesejado quando a lista fornecida énull

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));
}

Agora você pode agrupar por qualquer coisa com isso. Para o caso de uso aqui na questão

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

Talvez você queira dar uma olhada neste também Guia para agrupamento de Java 8 por coletor

Shafin Mahmud
fonte
4

Você pode usar o seguinte:

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);
}

//impressão

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);
    }
}
Azizi
fonte
4

Implemente o recurso SQL GROUP BY em Java usando o Comparator, o comparator irá comparar os dados da coluna e classificá-los. Basicamente, se você mantém os dados classificados que parecem dados agrupados, por exemplo, se você tem os mesmos dados de coluna repetidos, o mecanismo de classificação classifica-os mantendo os mesmos dados de um lado e, em seguida, procura outros dados que são dados diferentes. Isso é visto indiretamente como GROUPING dos mesmos dados.

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);
        }
    }
}

A saída está aqui para a lista de ProductBean acima feita com os critérios GROUP BY, aqui se você ver os dados de entrada que são fornecidos com a lista de ProductBean para Collections.sort (lista, objeto de Comparador para sua coluna necessária) Isso será classificado com base na implementação de seu comparador e você poderá ver os dados GROUPED na saída abaixo. Espero que isto ajude...

    ******** ANTES DE AGRUPAR DADOS DE ENTRADA PARECE ASSIM ******
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 30 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P2 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P3 60 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ******** APÓS O GRUPO POR PRODUCT_ID ******
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 30 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P2 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P3 60 Seg 17 de novembro 09:31:01 IST 2014]

    ******** APÓS O GRUPO POR PREÇO ******
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P2 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 20 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P1 30 Seg 17 de novembro 09:31:01 IST 2014]
    ProductBean [P3 60 Seg 17 de novembro 09:31:01 IST 2014]

Ravi Beli
fonte
1
Olá, por favor, não poste a mesma resposta várias vezes e não poste código bruto sem uma explicação sobre como funciona e como resolve o problema da pergunta acima.
Mat
Desculpe amigo, ocorreu um erro ao colar o código, pois pode ter se tornado várias vezes. Eu editei a explicação para o que postei. Espero que esteja bom agora ???
Ravi Beli
Estou faltando alguma coisa ou este código está classificando em vez de agrupar por um campo? Vejo os produtos classificados por ID e, em seguida, por Preço
Financiador
0

Você pode classificar assim:

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

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

Supondo que você também tenha o getter para localização em sua classe de aluno.

Pieter
fonte
3
Por que classificar? O problema é agrupar os elementos!
Sankalp,
0

Você poderia fazer isso:

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);

as chaves serão os locais e a lista de valores dos alunos. Mais tarde, você pode obter um grupo de alunos apenas usando:

studlist = map.get("New York");
Omoro
fonte
0

você pode usar guavao deMultimaps

@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 })

imprimir:

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

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

Se você quiser adicionar vários objetos para agrupar por, basta adicionar o objeto no compositKeymétodo separando por vírgula:

Function<Student, List<Object>> compositKey = std ->
                Arrays.asList(std.stud_location(),std.stud_name());
        studentList.stream().collect(Collectors.groupingBy(compositKey, Collectors.toList()));
TanvirChowdhury
fonte
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
}
Soudipta Dutta
fonte