4

I'm trying to find an elegant way to convert a Stream<String> to float[].

Until now I've come out with:

Float[] data = input.map(Float::valueOf).toArray(Float[]::new);

But I actually need a float[] and when I try:

float[] data = input.map(x -> Float.parseFloat(x)).toArray(size -> new float[]);

I get an error cannot convert Object[] to float[], which I don't really understand.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
Gianluca
  • 805
  • 1
  • 10
  • 20
  • What is the element type of the `input` stream? – ernest_k Jun 22 '18 at 16:44
  • 1
    There's no `FloatStream`, so I don't think this is possible without writing a custom collector which converts from either `Float` or `double`. – Radiodef Jun 22 '18 at 16:46
  • 1
    Would a `double[]` do? If so, you could use [`Stream#mapToDouble(...)`](https://docs.oracle.com/javase/10/docs/api/java/util/stream/Stream.html#mapToDouble(java.util.function.ToDoubleFunction)) to obtain a [`DoubleStream`](https://docs.oracle.com/javase/10/docs/api/java/util/stream/DoubleStream.html) – Turing85 Jun 22 '18 at 16:46
  • Why `float` and not `double`? Then you could use `DoubleStream`. – daniu Jun 22 '18 at 16:46
  • 3
    The duplicate is exactly not what OP wants. If anything, [this](https://stackoverflow.com/questions/41297869/converting-an-array-of-strings-to-an-array-of-floats-in-java) is what OP wants. But even this does not answer the question as to why it does not work. Voting to reopen. – Turing85 Jun 22 '18 at 16:55
  • I would say that it is not a duplicate. I've seen that answer and it didn't help to solve my problem. – Gianluca Jun 22 '18 at 17:13
  • There's another answer embedded in there. There is no way to get a primitive `float` out of a stream in this fashion. – Makoto Jun 22 '18 at 17:19
  • Use `mapToDouble(Float::parseFloat)` together with the collector of [this answer](https://stackoverflow.com/a/26970398/2711488). – Holger Jun 25 '18 at 14:10

4 Answers4

4

There is no way of getting float[] directly from any Stream in Java yet. There are "only" 3 available converting mechanisms to numeric Stream interfaces:

Thus the only way is to use double instead, which is fairly easy:

double[] data = input.mapToDouble(Double::parseDouble).toArray();

If you insist to get the float[] from double[], it's another issue where might help the Guava library:

float[] floatArray = Floats.toArray(Doubles.asList(data));
// You can collect Stream to a Collection and pass directly Floats.toArray(list);

Or a simple for-loop:

float[] floatArray = new float[data.length];
for (int i = 0 ; i < data.length; i++) {
    floatArray[i] = (float) data[i];
}

Alternatively, you might use the method toArray(IntFunction<A[]> generator) which returns the array of an Object type. However, to unbox Float, you have to use the for-loop again in the very same way - it gives no difference except you can work with Float[] directly, although boxed.

Here is the use:

Float[] data = input.map(Float::valueOf).toArray(Float[]::new);
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
3

There is a minor error in your code, which we will fix first to reveal the larger problem at hand:

float[] data = input.map(x -> Float.parseFloat(x)).toArray(size -> new float[]);

should be:

float[] data = input.map(x -> Float.parseFloat(x)).toArray(size -> new float[size]);
                                                                             ^this is new

Even if it might not seem like it, your question is realted to generics. Let us take a look at the definition of Stream#toArray(...):

public <A> A[] toArray​(IntFunction<A[]> generator)

Since this method is generic in A, the type A must not be a primitive. You, on the other hand, try to set A to float (this is done through type inference, this is why you do not see the generic parameters in your code). The compiler now complains that:

error: incompatible types: inference variable A has incompatible bounds
    float[] data = input.stream().map(x -> Float.parseFloat(x)).toArray(size -> new float[size]);
                                                                       ^
    equality constraints: float
    upper bounds: Object
  where A is a type-variable:
    A extends Object declared in method <A>toArray(IntFunction<A[]>)
1 error

This question and its answer provide solutions/workarounds to the problem of converting a String-stream to a float[].

Turing85
  • 18,217
  • 7
  • 33
  • 58
  • The missing size is actually a typo, in the code I have got it. I'll not fix the question or your answer will lose meaning. Thank you – Gianluca Jun 22 '18 at 20:56
3

There is a better way with my library abacus-common:

float[] result = Stream.of(input).mapToFloat(Float::parseFloat).toArray();
user_3380739
  • 1
  • 14
  • 14
  • Thank you for doing what the core Java library team couldn't be arsed to do. Single Precision is handy anywhere hardware acceleration is involved. – Akumaburn Dec 04 '20 at 01:51
0

You can use the value from the Float Object through the floatValue() method to create a array:

Float[] data = input.map(Float::valueOf).toArray(Float[]::new);
float[] primData = new float[data.length];

for(int x = 0; x < data.length; x ++) {
    primData[x] = data[x].floatValue();
}
Ryan
  • 1,972
  • 2
  • 23
  • 36