TilmannZ
TilmannZ

Reputation: 1889

Splitting an array into subarrays with java streams - stateful mapper

I have a double[] with K*N elements. I would like to split this into a stream (list/array/...) of N long[] arrays of size K. I already found a solution, but it looks quite dirty and requires a stateful Mapper (I think they are meant to be stateless):

private class DataToLong implements DoubleFunction<long[]> {
    int d = 0;
    long[] buf = new long[K];
    @Override
    public long[] apply(double value) {
        buf[d] = BitTools.toSortableLong(value);
        d++;
        long[] ret = null;
        if (d >= K) {
            ret = buf;
            buf = new long[K];
            d = 0;
        }
        return ret;
    }
}

public void load(double[] data, int K) {
    Arrays.stream(data).mapToObj(new DataToLong())
                            .filter((x)-> x != null).forEach((buf)->{
        //here we do something with 'buf'
    });
}

The above code seems to work, but it's actually longer than the non-streams version of the code and it violates the stateless requirements of the Mapper. It there any better way to achieve the same thing?

Upvotes: 2

Views: 1994

Answers (3)

TilmannZ
TilmannZ

Reputation: 1889

Here is another variant of @Louis Wasserman's answer, integrating a part from @srborlongan's answer. Tt avoids the 'new' and the loop:

IntStream.range(0, N)
  .mapToObj(
    i -> IntStream.range(0, DIM)
    .mapToLong(
      j -> pre(data[DIM * i + j])
    ).toArray()
  ).forEach(buf -> myFunction(buf));

Unfortunately, it seems to be 10-20% slower than @Louis Wasserman's solution

Upvotes: 1

srborlongan
srborlongan

Reputation: 4579

A variant of @Louis Wasserman's answer:

   IntStream.range(0, n)
     // for each int i, derive a DoubleStream that maps each
     // j in range(0, k) to the double in data[k * i + j]
     .mapToObj(
       i -> IntStream.range(0, k)
           .mapToDouble(j -> data[k * i + j])
     )
     // flatMap from Stream<DoubleStream> to DoubleStream 
     .flatMapToDouble(Function.identity())
     // call BitTools::toSortableLong on every double
     .mapToLong(BitTools::toSortableLong)
     // collect into a long[]
     .toArray()
   ;

Upvotes: 0

Louis Wasserman
Louis Wasserman

Reputation: 198033

IntStream.range(0, n).mapToObj(
   i -> {
     long[] arr = new long[k];
     for (int j = 0; j < k; j++) {
       arr[j] = BitTools.toSortableLong(data[k * i + j]);
     }
     return arr;
   });

Upvotes: 2

Related Questions