2

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?

3 Answers 3

2
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;
   });
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, that works fine and is much better than my solution. Can this easily be adapted to work so that I don't need to know 'n' it advance, for example if I read it from a file?
Not easily, I think; streams don't really easily support splitting on the fly like that?
Okay, thanks, that was more of a theoretical question (for now).
1

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

Comments

0

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()
   ;

1 Comment

Thanks, I'm just not sure how I can use the resulting array. For example how would I use the resulting long[] array as an argument to a function? For example how would I call doSomething(long [])? I don't think I could just use the whole stream as argument?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.