Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to .flatMap() or .collect() evenly multiple collections

For instance there are collections [1,2,3,4,5], [6,7,8], [9,0]. Any way to avoid loops with iterators to interleave these collections via Java 8 stream API to get the following result - [1,6,9,2,7,0,3,8,4,5]?

like image 317
igorp1024 Avatar asked Jun 08 '16 12:06

igorp1024


People also ask

What does the flatMap () function do?

flatMap() V/s map() : It applies a function on each element of Stream and store return value into new Stream. It does not flatten the stream. But flatMap() is the combination of a map and a flat operation i.e, it applies a function to elements as well as flatten them.

What is difference between flatMap () and map () functions?

Both of the functions map() and flatMap are used for transformation and mapping operations. map() function produces one output for one input value, whereas flatMap() function produces an arbitrary no of values as output (ie zero or more than zero) for each input value. Where R is the element type of the new stream.

What is diff between map flatMap and foreach?

The difference is that the map operation produces one output value for each input value, whereas the flatMap operation produces an arbitrary number (zero or more) values for each input value.

Does flatMap preserve order?

Does flatmap() method preserve the order of the streams? Yes, It does and map() also.


1 Answers

I am not sure if there's a simpler way with the Stream API, but you can do this using a stream over the indices of all the lists to consider:

static <T> List<T> interleave(List<List<T>> lists) {
    int maxSize = lists.stream().mapToInt(List::size).max().orElse(0);
    return IntStream.range(0, maxSize)
                    .boxed()
                    .flatMap(i -> lists.stream().filter(l -> i < l.size()).map(l -> l.get(i)))
                    .collect(Collectors.toList());
}

This gets the size of the greatest list in the given lists. For each index, it then flat maps it with a stream formed by the elements of each list at that index (if the element exist).

Then you can use it with

public static void main(String[] args) {
    List<Integer> list1 = Arrays.asList(1,2,3,4,5);
    List<Integer> list2 = Arrays.asList(6,7,8);
    List<Integer> list3 = Arrays.asList(9,0);
    System.out.println(interleave(Arrays.asList(list1, list2, list3))); // [1, 6, 9, 2, 7, 0, 3, 8, 4, 5]
}

Using the protonpack library, you can use the method interleave to do just that:

List<Stream<Integer>> lists = Arrays.asList(list1.stream(), list2.stream(), list3.stream());
List<Integer> result = StreamUtils.interleave(Selectors.roundRobin(), lists).collect(Collectors.toList());
System.out.println(result);
like image 52
Tunaki Avatar answered Oct 21 '22 17:10

Tunaki