Grupuj listę obiektów według atrybutu

101

Muszę zgrupować listę obiektów ( Student) przy użyciu atrybutu ( Location) określonego obiektu. Kod wygląda jak poniżej:

public class Grouping {
    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"));

    }
}

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

Proszę, zasugeruj mi czysty sposób, aby to zrobić.

Dilukshan Mahendra
źródło
2
Hashmap z lokalizacją jako kluczem, a uczniowie jako wartość.
Omoro,
Czy sortowanie według lokalizacji rozwiązałoby problem, czy jest coś innego?
Warlord
Spróbuj użyć komparatora i posortuj według lokalizacji.
pshemek
1
@Warlord Tak, ale idąc dalej, jeśli potrzebuję informacji, takich jak liczba uczniów według lokalizacji lepiej, gdybym mogła to pogrupować
Dilukshan Mahendra,
@Omoro Proszę, czy możesz podać mi wskazówkę za pomocą kodu, nie jestem zbyt zaznajomiony z Hashmaps
Dilukshan Mahendra

Odpowiedzi:

131

Spowoduje to dodanie obiektu do studentów HashMapz locationIDjak klucz.

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

Powtórz ten kod i dodaj uczniów do HashMap:

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

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

Jeśli chcesz, aby wszyscy uczniowie mieli określone szczegóły lokalizacji, możesz użyć tego:

hashMap.get(locationId);

dzięki czemu wszyscy uczniowie będą mieli ten sam identyfikator lokalizacji.

Dileep
źródło
4
Zadeklarowałeś listę obiektów lokalizacji, a w następnej linii dodajesz obiekt Studenta do poprzedniej listy, co powinno spowodować błąd.
OJVM
hashMap.get () zwraca wartość null, gdy funkcja hashMap.contanisKey () zwraca wartość false. Możesz zapisać wywołanie metody zawieraKey (), jeśli najpierw wywołasz hashMap.get (), zapiszesz wynik w lokalnej zmiennej i sprawdzisz, czy ta zmienna lokalna ma wartość null
Esteve
259

W Javie 8:

Map<String, List<Student>> studlistGrouped =
    studlist.stream().collect(Collectors.groupingBy(w -> w.stud_location));
Vitalii Fedorenko
źródło
Dzieje się tak, ponieważ w Studentklasie stud_locationjest określony jako przyjazny. Dostęp ma tylko Studentklasa i każda klasa zdefiniowana w tym samym pakiecie . Jeśli zamiast tego wstawisz , to powinno działać. Lub możesz zdefiniować funkcję pobierającą. Więcej informacji w 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);
    }

}
sampath challa
źródło
8

Korzystanie z języka 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
    }

}

Rezultatem będzie:

{
    Max={
        Los Angeles=[Student@214c265e], 
        California=[Student@448139f0]
    }, 
    John={
        New York=[Student@7cca494b]
    }, 
    Sam={
        California=[Student@7ba4f24f]
    }
}
Chirag
źródło
Tę odpowiedź można poprawić, trzymając się tego samego przykładu co pytanie. Również wynik nie zgadza się z żądanym wynikiem w pytaniu.
Pim Hazebroek
6

Grupowanie Java 8 przez Collector

Prawdopodobnie jest późno, ale lubię podzielić się ulepszonym pomysłem na ten problem. Jest to w zasadzie to samo, co odpowiedź @Vitalii Fedorenko, ale bardziej przydatne do zabawy.

Możesz po prostu użyć Collectors.groupingBy(), przekazując logikę grupowania jako parametr funkcji, a otrzymasz podzieloną listę z mapowaniem parametrów klucza. Zauważ, że użycie Optionaljest używane, aby uniknąć niechcianego NPE, gdy podana lista jestnull

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

Teraz możesz grupować wszystko za pomocą tego. W przypadku użycia tutaj w pytaniu

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

Może chciałbyś zajrzeć do tego Przewodnika po grupowaniu Java 8 przez Collector

Shafin Mahmud
źródło
4

Możesz użyć następujących:

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

//wydrukować

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
źródło
4

Zaimplementuj funkcję SQL GROUP BY w Javie za pomocą komparatora, komparator porówna dane kolumny i posortuje je. Zasadniczo, jeśli przechowujesz posortowane dane, które wyglądają jak dane zgrupowane, na przykład jeśli masz te same powtarzające się dane w kolumnach, mechanizm sortowania sortuje je, zachowując te same dane po jednej stronie, a następnie szuka innych danych, które są niepodobnymi danymi. To pośrednio postrzegane jako GRUPOWANIE tych samych danych.

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

Wynik jest tutaj dla powyższej listy ProductBean jest wykonywana według kryteriów GROUP BY, tutaj, jeśli zobaczysz dane wejściowe, które są podane jako lista ProductBean do kolekcji. Sortowanie (lista, obiekt komparatora dla wymaganej kolumny) To zostanie posortowane na podstawie implementacji twojego komparatora i będziesz mógł zobaczyć dane ZGRUPOWANE w poniższym wyniku. Mam nadzieję że to pomoże...

    ******** PRZED GRUPOWANIE DANYCH WEJŚCIOWYCH WYGLĄDA TAKIEGO ******
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    ProductBean [P1 30 Mon, 17 listopada, 09:31:01, IST 2014]
    Fasola Produktowa [P2 20 Pon, 17 Lis, 09:31:01, IST 2014]
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    ProductBean [P3 60 Mon, 17 listopada, 09:31:01, IST 2014]
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    ******** PO GRUPOWANIE WEDŁUG ID PRODUKTU ******
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    ProductBean [P1 30 Mon, 17 listopada, 09:31:01, IST 2014]
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    Fasola Produktowa [P2 20 Pon, 17 Lis, 09:31:01, IST 2014]
    ProductBean [P3 60 Mon, 17 listopada, 09:31:01, IST 2014]

    ******** PO GRUPOWANIU WEDŁUG CENY ******
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    Fasola Produktowa [P2 20 Pon, 17 Lis, 09:31:01, IST 2014]
    Fasola Produktowa [P1 20 Pon 17 Lis 09:31:01 IST 2014]
    ProductBean [P1 30 Mon, 17 listopada, 09:31:01, IST 2014]
    ProductBean [P3 60 Mon, 17 listopada, 09:31:01, IST 2014]

Ravi Beli
źródło
1
Cześć, nie publikuj wielokrotnie tej samej odpowiedzi i nie wysyłaj surowego kodu bez wyjaśnienia, jak to działa i jak rozwiązuje problem z powyższego pytania.
Mat
Przepraszam kolego, podczas wklejenia kodu wystąpił błąd, ponieważ mógł wystąpić wiele razy. Zredagowałem wyjaśnienie tego, co opublikowałem. Mam nadzieję, że teraz wygląda dobrze ???
Ravi Beli
Brakuje czegoś lub ten kod sortuje zamiast grupować według pola? Widzę produkty posortowane według identyfikatora, a następnie ceny
funder7
1
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
źródło
0

Możesz sortować w ten sposób:

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

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

Zakładając, że masz również narzędzie pobierające lokalizację w klasie ucznia.

Pieter
źródło
4
Dlaczego sortować? Problemem jest pogrupowanie elementów!
Sankalp
0

Możesz to zrobić:

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

kluczami będą lokalizacje i lista wartości uczniów. Więc później możesz zdobyć grupę uczniów, używając tylko:

studlist = map.get("New York");
Omoro
źródło
0

możesz użyć 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 })

to drukuje:

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

jiahut
źródło
0
Function<Student, List<Object>> compositKey = std ->
                Arrays.asList(std.stud_location());
        studentList.stream().collect(Collectors.groupingBy(compositKey, Collectors.toList()));

Jeśli chcesz dodać wiele obiektów do grupowania, możesz po prostu dodać obiekt w compositKeymetodzie oddzielając przecinkami:

Function<Student, List<Object>> compositKey = std ->
                Arrays.asList(std.stud_location(),std.stud_name());
        studentList.stream().collect(Collectors.groupingBy(compositKey, Collectors.toList()));
TanvirChowdhury
źródło