Given a List<Integer> l
and a factor int f
, I would like to use a stream to create a Map<Integer, Map<Integer, Long>> m
such that the parent map has keys that are the index within l
divided by f, and the value is a map of values to counts.
If the list is {1,1,1,4}
and the factor is f=2
I would like to get:
0 ->
{
1 -> 2
}
1 ->
{
1 -> 1
4 -> 1
}
Basically, I'm hoping for a stream version of:
Map<Integer, Map<Integer, Long>> m = new HashMap<>();
for (int i = 0; i < l.size(); i++) {
m.computeIfAbsent(i/f, k -> new HashMap<>())
.compute(l.get(i), (k, v) -> v==null?1:v+1);
}
I realize it is fairly similar to this question about collecting a map of maps and I understand how to do a much simpler groupingBy
with a count:
Map<Integer, Long> m = l.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
But I do not understand how to put those two ideas together without iterating.
Because I am working with indexes as one of the keys, I imagine that rather than starting with l.stream()
I will start with IntStream.range(0, l.size()).boxed()
which lets me get the first key (i -> i/f
) and the second key(i -> l.get(i)
), but I still don't know how to properly collect the counts.
Here is a solution.
public static void main(String[] args) {
final List<Integer> l = List.of(1,1,1,4);
final int f = 2;
final var value = IntStream.range(0,l.size())
.boxed()
.collect(Collectors.groupingBy(i -> i/f, Collectors.groupingBy(l::get, Collectors.counting())));
System.out.println(value);
}
Not sure if this is a personal requirement, but sometime using standard loops over streams is not necessarily a bad thing.