Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8: grouping by multiple fields and then sort based on value

I have a class called Info

public class Info {
    private String account;
    private String opportunity;
    private Integer value;
    private String desc;
}

I want to group a list of Info, by two fields(account and then opportunity) and then sort it based on value. i.e. List of info before grouping and sorting:

List<Info> infos = [(account = 1234, opportunity = abs, value = 4, desc= test),
(account = 1234, opportunity = abs, value = 5, desc = testing),
(account = 1234, opportunity = abss, value = 10, desc = vip),
(account = 123, opportunity = abss, value = 8, desc = vip),
(account = 12, opportunity = absddd, value = 4, desc = production),
(account = 12, opportunity = absooo, value = 2, desc = test)]

The result I expected after grouping and sorting,

Map<String, Map<String, List<Info>>> result = {
    1234 = {
        abss = [(account = 1234, opportunity = abss, value = 10, desc = vip)],
        abs = [(account = 1234, opportunity = abs, value = 5, desc = testing),  
               (account = 1234, opportunity = abs, value = 4, desc = test)]
    },
    123 = {
        abss = [(account = 123, opportunity = abss, value = 8, desc = vip)]
    },
    12 = {
        absddd = [(account = 12, opportunity = absddd, value = 4, desc = production)],
        absooo = [(account = 12, opportunity = absooo, value = 2, desc = test)]
    }
}

o/p is sorted based on value(10->(5+4)->8->4->2)

I have tried so far = infos.stream().collect(Collectors.groupingBy(Info::getAccount, Collectors.groupingBy(r -> r.getOpportunity(), Collectors.toList()))) but its sorting randomly.

like image 656
wasim sarkar Avatar asked Aug 09 '26 07:08

wasim sarkar


1 Answers

To sort base on the value of Info,

  1. Make the stream sorted, by comparing the value, such that grouping will execute in order.
  2. When calling groupingBy, Specify LinkedHashMap in mapFactory to preserve the insertion order .

Following program demonstrates how to implement.


import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Info {
    private String account;
    private String opportunity;
    private Integer value;
    private String desc;

    private Info(String account, String opportunity, Integer value, String desc) {
        super();
        this.account = account;
        this.opportunity = opportunity;
        this.value = value;
        this.desc = desc;
    }

    public static void main(String[] args) {
        List<Info> infos = new ArrayList<>();
        infos.add(new Info("12", "absddd", 4, "production"));
        infos.add(new Info("1234", "abss", 10, "vip"));
        infos.add(new Info("1234", "abs", 4, "test"));
        infos.add(new Info("1234", "abs", 5, "testing"));
        infos.add(new Info("123", "abss", 8, "vip"));
        infos.add(new Info("12", "absooo", 2, "test"));
        Map<String, Map<String, List<Info>>> sortedResult = infos.stream().sorted(Info::compareByValueDesc)
                .collect(Collectors.groupingBy(Info::getAccount, LinkedHashMap::new,
                        Collectors.groupingBy(r -> r.getOpportunity(), LinkedHashMap::new, Collectors.toList())));
        sortedResult.forEach((key, value) -> System.out.println(key + value.toString()));
    }

    public static int compareByValueDesc(Info other1, Info other2) {
        return -other1.value.compareTo(other2.value);
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getOpportunity() {
        return opportunity;
    }

    public void setOpportunity(String opportunity) {
        this.opportunity = opportunity;
    }

    public String toString() {
        return this.value.toString();
    }
}
like image 148
samabcde Avatar answered Aug 11 '26 21:08

samabcde