wasim sarkar
wasim sarkar

Reputation: 33

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.

Upvotes: 3

Views: 5625

Answers (1)

samabcde
samabcde

Reputation: 8124

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

Upvotes: 3

Related Questions