4

I'm trying to convert an ArrayList containing float values to an array of primitive floats using the Java 8 Stream API. What I tried so far looked something like this:

List<Float> floatList = new ArrayList<Float>(); 
float[] floatArray = floatList.stream().map(i -> i).toArray(float[]::new)
Jonathan Hunz
  • 87
  • 1
  • 7
  • 3
    So what the problem is? – Master Yoda Sep 11 '17 at 16:21
  • 3
    If a `double[]` is sufficient you can use `floatList.stream().mapToDouble(f -> f.doubleValue()).toArray();`. `float` is a bit of an archaic type. – OldCurmudgeon Sep 11 '17 at 16:25
  • 4
    Since they didn't add a `FloatStream`, only a [`DoubleStream`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/DoubleStream.html), you can only do this by writing your own [`Collector`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collector.html). – Andreas Sep 11 '17 at 16:26
  • 3
    Not a dup, but related: [https://stackoverflow.com/questions/718554/how-to-convert-an-arraylist-containing-integers-to-primitive-int-array](https://stackoverflow.com/questions/718554/how-to-convert-an-arraylist-containing-integers-to-primitive-int-array) – code_dredd Sep 11 '17 at 16:27
  • 3
    https://stackoverflow.com/a/26970398/2711488 – Holger Sep 11 '17 at 16:59

4 Answers4

9

Honestly: there's no good built-in way to do this with streams. Sorry, but it's the truth.

If you can live with a double[], you can use floatList.stream().mapToDouble(f -> f.doubleValue()).toArray(), but that's probably not what you're hoping for.

If you want to do it with streams, you'll need to write your own custom resizing list type and collect to it, but nothing short of that is going to work. You'd have to write something like

float[] toFloatArray(Collection<Float> collection) {
  class FloatArray {
    int size;
    float[] array;
    FloatArray() {
      this.size = 0;
      this.array = new float[10];
    }
    void add(float f) {
      if (size == array.length) {
        array = Arrays.copyOf(array, array.length * 2);
      }
      array[size++] = f;
    }
    FloatArray combine(FloatArray other) {
      float[] resultArray = new float[array.length + other.array.length];
      System.arraycopy(this.array, 0, resultArray, 0, size);
      System.arraycopy(other.array, 0, resultArray, size, other.size);
      this.array = resultArray;
      this.size += other.size;
      return this;
    }
    float[] result() {
      return Arrays.copyOf(array, size);
    }
  }
  return collection.stream().collect(
     Collector.of(
         FloatArray::new, FloatArray::add, 
         FloatArray::combine, FloatArray::result));
}

It'd be much simpler to convert your collection directly to a float[] without streams, either by yourself with a straightforward loop --

float[] result = new float[collection.size()];
int i = 0;
for (Float f : collection) {
  result[i++] = f;
}

or with a third-party library, e.g. Guava's Floats.toArray.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
4

How about this? You can use FloatBuffer to collect the float[], for example:

float[] result = floatList.stream().collect(
  ()-> FloatBuffer.allocate(floatList.size()), 
  FloatBuffer::put,
  (left, right) -> { 
     throw new UnsupportedOperationException("only be called in parallel stream");
  }
).array();
holi-java
  • 29,655
  • 7
  • 72
  • 83
3

If you use Eclipse Collections Collectors2 with the Stream collect method, you can accomplish this.

ArrayList<Float> floats = new ArrayList<>();
floats.add(new Float(1.0f));
floats.add(new Float(2.0f));
floats.add(new Float(3.0f));
float[] floatArray =
        floats.stream()
                .collect(Collectors2.collectFloat(
                                Float::floatValue,
                                FloatLists.mutable::empty))
                .toArray();

You can also accomplish this without using Streams by using the LazyIterate class.

float[] array =
    LazyIterate.adapt(floats).collectFloat(Float::floatValue).toArray();

If you use the built in primitive collections, you can simply convert a FloatList to a float array as follows:

float[] array = FloatLists.mutable.with(1.0f, 2.0f, 3.0f).toArray();

Note: I am a committer for Eclipse Collections.

Donald Raab
  • 6,458
  • 2
  • 36
  • 44
1

It's not possible to convert an Object[] to a primitive array(float [] in your case).

Alternate way possible(assuming Nonnull values) could be as:

Object[] arr = floatList.toArray();
for (Object o : arr) {
    System.out.println((float)o);
}

Commons from apache provides a util for it though ArrayUtils.toPrimitive()

Naman
  • 27,789
  • 26
  • 218
  • 353
  • 3
    You can't cast an `Object[]` to a `Float[]` it will throw a `ClassCastException` – Jorn Vernee Sep 11 '17 at 16:30
  • 2
    I mean, it is possible with streams, just only for `int[]`, `long[]`, and `double[]`. And you'd have to write `floatList.toArray(new Float[0])`, you can't do that cast. – Louis Wasserman Sep 11 '17 at 16:30