3

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.

samabcde
  • 6,988
  • 2
  • 25
  • 41
wasim sarkar
  • 33
  • 1
  • 5

1 Answers1

3

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();
    }
}
samabcde
  • 6,988
  • 2
  • 25
  • 41
  • thanks for the reply. but i am facing issue while trying to satisfy below input `infos.add(new Info("12", "absddd", 4, "production")); infos.add(new Info("1234", "abss", 11, "vip")); infos.add(new Info("12345", "abs", 4, "test")); infos.add(new Info("12345", "abs", 5, "testing")); infos.add(new Info("123", "abss", 8, "vip")); infos.add(new Info("12", "absooo", 2, "test"));` in this case output is coming as `1234{abss=[11]} 123{abss=[8]} 12345{abs=[5, 4]} 12{absddd=[4], absooo=[2]}`; which is not sorted – wasim sarkar Sep 14 '20 at 06:51
  • What are you expecting for such case? Is there any criteria I missed(It seems correct to me)? – samabcde Sep 14 '20 at 06:56
  • i want to sort it based on groupingby and summingLong, in the above comment the input that i have mentioned, for which the o/p should be `1234{abss=[11]} 12345{abs=[5, 4]} 123{abss=[8]} 12{absddd=[4], absooo=[2]}` – wasim sarkar Sep 14 '20 at 06:57
  • It seems I misunderstand what you need, I suggest you to edit your post to provide the ordering you needed for 1. account group entry, 2. opportunity group entry, 3. values in opportunity group. – samabcde Sep 14 '20 at 07:04
  • true, the one which i am asking for is not possible to get by map of map. trying different process. – wasim sarkar Sep 14 '20 at 07:35