Reputation: 53
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?
Upvotes: 5
Views: 1491
Reputation: 298389
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.
Upvotes: 2
Reputation: 27976
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())
Upvotes: 4