How to get an ObservableFloatArray from a Stream?

前端 未结 2 1901
孤街浪徒
孤街浪徒 2020-12-06 19:14

This is nearly the same question as this one, but in the opposite direction.

I know there\'s no FloatStream in Java 8, and there\'re no many use cases f

相关标签:
2条回答
  • 2020-12-06 19:54

    I don't think there's any way around the fact that you have to create one data structure (e.g. a double[] or a List<Float>) and then map it into a float[]. (But maybe I am missing something.)

    If you want to do this using a Stream-like API, you can use a Collector to do the mapping at the end:

    import java.util.List;
    import java.util.ListIterator;
    import java.util.Random;
    import java.util.stream.Collector;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    import java.util.stream.Stream;
    
    import javafx.scene.shape.TriangleMesh;
    
    public class StreamFloatsTest {
    
        public static void main(String[] args) {
    
            // The following declaration works in Eclipse 4.4
            // however it won't compile from the command line:
            // Collector<Float, List<Float>, float[]> toFloatArray =
    
            // This declaration works:
    
            Collector<Float, ?, float[]> toFloatArray =
                    Collectors.collectingAndThen(Collectors.toList(), floatList -> {
                        float[] array = new float[floatList.size()];
                        for (ListIterator<Float> iterator = floatList.listIterator(); iterator.hasNext();) {
                            array[iterator.nextIndex()] = iterator.next();
                        }
                        return array ;
                    });
    
    
            // Random vertex list for demo purposes:
            Random rng = new Random();
            List<Vertex> vertices = IntStream.range(0, 100)
                    .mapToObj(i -> new Vertex(rng.nextFloat(), rng.nextFloat(), rng.nextFloat()))
                    .collect(Collectors.toList());
    
            float[] vertexArray = vertices.stream()
                    .flatMap(v -> Stream.of(v.getX(), v.getY(), v.getZ()))
                    .collect(toFloatArray);
    
    
            TriangleMesh mesh = new TriangleMesh();
    
            mesh.getPoints().addListener(obs -> System.out.println("mesh invalidated"));
            mesh.getPoints().addListener((array, sizeChanged, from, to) -> System.out.println("mesh changed"));
            mesh.getPoints().addAll(vertexArray);
    
        }
    
        public static class Vertex {
            private final float x ;
            private final float y ;
            private final float z ;
            public Vertex(float x, float y, float z) {
                this.x = x ;
                this.y = y ;
                this.z = z ;
            }
            public float getX() {
                return x;
            }
            public float getY() {
                return y;
            }
            public float getZ() {
                return z;
            }
            public float[] getCoordinates() {
                return new float[] {x, y, z};
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-06 20:17

    Keep in mind that a Stream defines an operation rather that a storage. So for most operations, using a float provides only little benefit over double values when CPU registers are used. There might be a theoretical improvement for operations that could be accelerated using SSE or GPU, but that’s not relevant here.

    So you can use a DoubleStream for that operation, the only thing you need is a collector capable of collecting a DoubleStream into a float[] array:

    float[] arrayVertices = listVertices.stream()
        .flatMapToDouble(vertex->DoubleStream.of(vertex.x, vertex.y, vertex.z))
        .collect(FaCollector::new, FaCollector::add, FaCollector::join)
        .toArray();
    
    static class FaCollector {
        float[] curr=new float[64];
        int size;
        void add(double d) {
            if(curr.length==size) curr=Arrays.copyOf(curr, size*2);
            curr[size++]=(float)d;
        }
        void join(FaCollector other) {
            if(size+other.size > curr.length)
                curr=Arrays.copyOf(curr, size+other.size);
            System.arraycopy(other.curr, 0, curr, size, other.size);
            size+=other.size;
        }
        float[] toArray() {
            if(size!=curr.length) curr=Arrays.copyOf(curr, size);
            return curr;
        }
    }
    

    This supports parallel processing, however, for an operation that merely consist of data copying only, there is no benefit from parallel processing.

    0 讨论(0)
提交回复
热议问题