Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cartesian product of two int arrays using Java 8 streams

I have two arrays of int, a = {10,20,30} and {1,2,3}.

I would like to get the Cartesian product of these two arrays.

When I use List of Integers the logic works fine:

    List<Integer> intList = Arrays.asList(10,20,30);
    List<Integer> intList1 = Arrays.asList(1,2,3);
    intList.stream().flatMap(i -> intList1.stream().map(j -> new int[]{i,j})).collect(Collectors.toList());

However, when I use int[], I'm getting compilation error.

Error:(16, 79) java: incompatible types: bad return type in lambda expression no instance(s) of type variable(s) U exist so that java.util.stream.Stream conforms to java.util.stream.IntStream

    int[] intArray = {10,20,30};
    int[] intArray1 = {1,2,3};
    Arrays.stream(intArray).flatMap(i -> Arrays.stream(intArray1).mapToObj(j -> new int[]{j,i})).collect(Collectors.toList());

Please help me to understand what is wrong here.

P. S.

Arrays.stream(intArray).mapToObj(i -> new int[]{i,i+1}).collect(Collectors.toList());

Produces the out put as, {(10,11),(20,21),(30,31)}.

like image 730
jegadeesh Avatar asked Jun 29 '18 15:06

jegadeesh


1 Answers

In the second case, Arrays.stream(intArray) returns an IntStream.
So flatMap() expects as parameter a stream compatible to :

Arrays.stream(intArray)
      .flatMap(i -> Arrays.stream(intArray1)
                     .mapToObj(j -> new int[] { j, i }))

But the lambda of flatMap() produces a Stream<int[]> and you cannot map a IntStream to a Stream implicitly.
Whereas the compilation error.
So first map your IntStream to Stream<Integer> :

List<int[]> collect = 
Arrays.stream(intArray)
      .boxed()
      .flatMap(i -> Arrays.stream(intArray1)
                          .mapToObj(j -> new int[] { j, i }))
      .collect(Collectors.toList());

It is less efficient than your initial intention (because of the Integer boxing) but it will work.
Note that generally, you have to avoid creating a List of array. These are not designed to work well together.
it is true in general and for streams too.

Edit

The Holger solution provided as a comment prevents the boxing :

List<int[]> collect = Arrays.stream(intArray)
                                  .mapToObj(i -> Arrays.stream(intArray1)
                                                       .mapToObj(j -> new int[] { j, i }))
                                  .flatMap(Function.identity())
                                  .collect(Collectors.toList());

It maps first the IntStream to a Stream<Stream<int[]>> and then flatMap() is invoked to amalgamate it into a <Stream<int[]>.

like image 59
davidxxx Avatar answered Oct 21 '22 05:10

davidxxx