tshymbra
tshymbra

Reputation: 53

Java 8: vertical slicing an array of Lists

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

Answers (2)

Holger
Holger

Reputation: 298389

Here is a solution which does not insert padding values for shorter Lists:

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

sprinter
sprinter

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

Related Questions