1

This question is related to How do I copy a 2 Dimensional array in Java?

But how would you copy an array using streams in Java 8 / 9?

This is what I came up with:

static int[][] cloneArray(int[][] array) {
    return IntStream.range(0, array.length).collect(
            () -> new int[array.length][],
            (ints, i) -> ints[i] = array[i].clone(),
            (ints, i) -> {});
}

Is there a more elegant or performant way to copy a 2D array using streams?

gil.fernandes
  • 12,978
  • 5
  • 63
  • 76
  • 2
    Why do you box the ints? That's gonna kill the performance definitely. – Kayaman Jan 03 '18 at 09:19
  • 1
    Can't really see how this is an improvement on the various non-stream ways, unless your intention is to make your code slower and much harder to read. – khelwood Jan 03 '18 at 09:22
  • @Kayaman: yes, that is silly. I have updated the question. – gil.fernandes Jan 03 '18 at 09:29
  • @khelwood; I have removed boxing. Why is performance so much slower? – gil.fernandes Jan 03 '18 at 09:36
  • I think the issue here is assuming that streams would somehow provide a better or faster way. A basic task like array copying is already solved efficiently, there are no huge advantages to be had. – Kayaman Jan 03 '18 at 09:48
  • @Kayaman: I was just exploring the possibility of solving this problem with streams - no explicit assumption was expressed in the question in terms of which solution is better. I agree that this problem has been already efficiently solved without streams. – gil.fernandes Jan 03 '18 at 09:56

2 Answers2

4
return Arrays.stream(x).map(r->Arrays.copyOf(r, r.length)).toArray(int[][]::new);

I think this is an improvement because you're not allocating a nxm array then replacing all of the m length ones with a copy.

matt
  • 10,892
  • 3
  • 22
  • 34
  • I like it, because it is very compact. But what about performance? – gil.fernandes Jan 03 '18 at 09:35
  • You're not double allocating in this way. You could probably improve your attempt by replacing the `.clone` call with `System.arraycopy` or at the very least, ditch the `array[0].length` and leave that part empty. – matt Jan 03 '18 at 09:39
  • Is `.clone` slower than `System.arraycopy`? Thank you for the suggestion to leave the `array[0].length` empty. – gil.fernandes Jan 03 '18 at 09:42
  • You'll have trouble measuring the difference, as per this question. https://stackoverflow.com/questions/12157300/clone-or-arrays-copyof Although in your case for a 2D array, where each row is the same length, I suspect they `System.arraycopy` will be the fastest because it allocates everything upfront. – matt Jan 03 '18 at 09:45
2

You can do it straight-forwardly using

static int[][] cloneArray(int[][] x) {
    return Arrays.stream(x).map(int[]::clone).toArray(int[][]::new);
}

Note that this works for any ElementType with a public method ElementType clone(), like

static ElementType[] cloneArray(ElementType[] x) {
    return Arrays.stream(x).map(ElementType::clone).toArray(ElementType[]::new);
}

and in your case, ElementType happens to be int[].

Holger
  • 285,553
  • 42
  • 434
  • 765