I want to use streams in java to group long list of objects based on multiple fields. This will result in map of map of map of map of map of .... of map of lists.
How can I only extract lists from that complex stream?
Here is some example code for demonstration (list of strings, looking for groups with same length and first letter). I'm not interested in keys, just in resulting grouped entities.
List<String> strings = ImmutableList.of("A", "AA", "AAA", "B", "BB", "BBB", "C", "CC", "CCC", "ABA", "BAB", "CAC");
Map<Character, Map<Integer, List<String>>> collect = strings.stream().collect(
groupingBy(s -> s.charAt(0),
groupingBy(String::length)
)
);
This will produce following result
My Map =
{
A =
{
1 = [A]
2 = [AA]
3 = [AAA, ABA]
}
B =
{
1 = [B]
2 = [BB]
3 = [BBB, BAB]
}
C =
{
1 = [C]
2 = [CC]
3 = [CCC, CAC]
}
}
What I'm interested in is actually just lists from the above results and I want to do it ideally as part of groupby operation. I know it can be done for example by looping resulting maps structure. But is there a way to achieve it using streams?
[
[A],
[AA],
[AAA, ABA],
[B],
[BB],
[BBB, BAB],
[C],
[CC],
[CCC, CAC]
]
Instead of creating nested groups by using cascaded Collectors.groupingBy
, you should group by a composite key:
Map<List<Object>, List<String>> map = strings.stream()
.collect(Collectors.groupingBy(s -> Arrays.asList(s.charAt(0), s.length())));
Then, simply grab the map values:
List<List<String>> result = new ArrayList<>(map.values());
If you are on Java 9+, you might want to change from Arrays.asList
to List.of
to create the composite keys.
This approach works very well for your case because you stated that you were not interested in keeping the keys, and because the List
implementation returned by both Arrays.asList
and List.of
are well-defined in terms of their equals
and hashCode
methods, i.e. they can be safely used as keys in any Map
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With