I'm learning Java 8 lambdas and streams. So, I got an array of lists having varying lengths. Lists contain integers.
What would be the best way to collect vertical slices in another list of lists i.e collect all integers with index 0 from all original lists in slice 0, index 1 in slice 1 and so an until the length of the longest list (filling zeros for shorter lists)
I know it's trivial to hand code a couple of traditional loops for this but what about doing this using Java 8 features?
That's a pretty interesting question - thanks for posting. I'm sure you'll see some interesting answers. Here's my attempt:
List<Integer> source[];
List<List<Integer>> slices = IntStream.range(0, Arrays.stream(source).mapToInt(List::size).max().getAsInt())
.mapToObj(index -> Arrays.stream(source).map(list -> list.size() > index ? list.get(index) : 0)
.collect(Collectors.toList()))
.collect(Collectors.toList())
Here is a solution which does not insert padding values for shorter List
s:
List<List<Integer>> slices = Stream.of(source).flatMap(l->
IntStream.range(0, l.size()).mapToObj(i->new int[]{i, l.get(i)})
).collect(collectingAndThen(
groupingBy(a->a[0], TreeMap::new, mapping(a->a[1], toList())),
m->new ArrayList<>(m.values()))
);
this can be expanded to a zero-padding version like this:
int maxSize=IntStream.range(0,source.length).map(i->source[i].size()).max().orElse(0);
List<List<Integer>> slices = Stream.of(source).flatMap(l->
Stream.concat(
IntStream.range(0, l.size()).mapToObj(i->new int[]{i, l.get(i)}),
IntStream.range(l.size(), maxSize).mapToObj(i->new int[]{i, 0})
)
).collect(collectingAndThen(
groupingBy(a->a[0], TreeMap::new, mapping(a->a[1], toList())),
m->new ArrayList<>(m.values()))
);
Both solutions assume that you do import static java.util.stream.Collectors.*;
as otherwise the code becomes really unreadable.
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