2

I have a list of elements. I want to group the elements of this list into a list of list based on some condition. Is it possible to do it easily in java ?

public class CollectionTest {

    public static void main(String[] arg) {
        Target target0 = new Target();
        target0.setRisklevel("III");
        target0.setLocation("Combined");
        Target target1 = new Target();
        target1.setRisklevel("III");
        target1.setLocation("Combined");
        Target target2 = new Target();
        target2.setRisklevel("III");
        target2.setLocation("Combined");
        Target target3 = new Target();
        target3.setRisklevel("III");
        target3.setLocation("Combined");
        Target target4 = new Target();
        target4.setRisklevel("IV");
        target4.setLocation("Combined");
        Target target5 = new Target();
        target5.setRisklevel("IV");
        target5.setLocation("Combined");
        Target target6 = new Target();
        target6.setRisklevel("IV");
        target6.setLocation("Combined");
        Target target7 = new Target();
        target7.setRisklevel("II");
        target7.setLocation("Domestic");
        Target target8 = new Target();
        target8.setRisklevel("IV");
        target8.setLocation("Domestic");
        Target target9 = new Target();
        target9.setRisklevel("IV");
        target9.setLocation("Domestic");
        Target target10 = new Target();
        target10.setRisklevel("IV");
        target10.setLocation("Domestic");
        Target target11 = new Target();
        target11.setRisklevel("IV");
        target11.setLocation("Domestic");

        List<Target> ucrtargetList = new ArrayList<Target>();
        ucrtargetList.add(target0);
        ucrtargetList.add(target1);
        ucrtargetList.add(target2);
        ucrtargetList.add(target3);
        ucrtargetList.add(target4);
        ucrtargetList.add(target5);
        ucrtargetList.add(target6);
        ucrtargetList.add(target7);
        ucrtargetList.add(target8);
        ucrtargetList.add(target9);
        ucrtargetList.add(target10);
        ucrtargetList.add(target11);
        List<List<Target>> fullList = new ArrayList<List<Target>>();
    }
}

Here condition is RiskLevel and Location has to be same in each list in the list of List. So fullList should have 4 lists within it(1st III & Combined, 2nd IV & Combined, 3rd II & Domestic, 4th IV & Domestic).

I could loop through the list and set the values. Is there an easier way to do this with java8 or apache commons ?

Pushpesh Kumar Rajwanshi
  • 18,127
  • 2
  • 19
  • 36
minusSeven
  • 224
  • 4
  • 13
  • Possible duplicate of [Group by multiple field names in java 8](https://stackoverflow.com/questions/28342814/group-by-multiple-field-names-in-java-8) – LuCio Oct 22 '18 at 09:07

3 Answers3

1

Unable to comment yet, so adding an answer, to extend what @Schidu Luca has replied, 'groupingBy' clauses can be chained, like this

Map<String, List<Target>> collect = ucrtargetList.stream()
           .collect(Collectors.groupingBy(Target::getRisklevel, Collectors.groupingBy(Target::getLocation)));
keybored
  • 129
  • 2
  • Now this returns a key that is RiskLevel and value as hashmaps which again has key as location. Any simple way to get a list of list from this hashmap ? – minusSeven Oct 22 '18 at 09:21
  • this is well explained here, in the answer by @Holger [link]https://stackoverflow.com/questions/38360276/convert-map-of-maps-into-lists-using-java-8-streams[link] – keybored Oct 22 '18 at 10:57
1

According to your description fullList should have 4 lists within it(1st III & Combined, 2nd IV & Combined, 3rd II & Domestic, 4th IV & Domestic) I assume your looking for this:

Function<Target, List<String>> riskLevelAndLocation = t -> List.of(t.getRiskLevel(), t.getLocation());
Map<List<String>, List<Target>> fullList = ucrtargetList.stream()
        .collect(Collectors.groupingBy(riskLevelAndLocation));

riskLevelAndLocation is a Function which retruns a List containing riskLevel and location. groupingBy a List works because List.equals(Object o)

Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal.

A quick check:

for (Entry<List<String>, List<Target>> entrySet : fullList.entrySet()) {
    System.out.println(entrySet.getKey().toString() + ": " + entrySet.getValue().size());
}

The output is:

[IV, Combined]: 3
[II, Domestic]: 1
[III, Combined]: 4
[IV, Domestic]: 4

If fullList has to have the order you've described then you could use a LinkedHashMap and sort it.

LuCio
  • 5,055
  • 2
  • 18
  • 34
  • This works but this seems to be using java10 features. I need solution in java 8 or using external libraries like Apache Commons. – minusSeven Oct 22 '18 at 13:46
  • The Java 9 code is `List.of`. You can use `Arrays.asList` instead. – LuCio Oct 22 '18 at 14:25
0
List<List<Target>> fullList = ucrtargetList.stream()
                .collect(Collectors.groupingBy(Target::getRisklevel)) // Or another collector
                .entrySet()
                .stream()
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());

If you want to remove the same objects from the result, you need to add methods 'equals' and 'hashcode' and collects to Set.

Ilya
  • 720
  • 6
  • 14