Sorting 2D array in new 2D array (K-means clustering)

前端 未结 3 1504
心在旅途
心在旅途 2021-01-21 21:32

As input I have a 2D array PointXY[][] clusters, which looks like this:

[[23.237633,53.78671], [69.15293,17.138134], [23.558687,45.70517]] . . .
[[47         


        
3条回答
  •  不要未来只要你来
    2021-01-21 22:19

    See another answer: Sorting a 2d array of objects by columns starting from the second row and transposing an array


    Building sorted cluster. First row are the center points. Other points are grouped by the nearest center. In this case all points are grouped by the second center point:

    PointXY[][] clusters = {
            {new PointXY(23.237633, 53.78671),
                    new PointXY(69.15293, 17.138134),
                    new PointXY(23.558687, 45.70517)},
            {new PointXY(47.851738, 16.525734),
                    new PointXY(47.802097, 16.689285),
                    new PointXY(47.946404, 16.732542)},
            {new PointXY(47.89601, 16.638218),
                    new PointXY(47.833263, 16.478987),
                    new PointXY(47.88203, 16.45793)},
            {new PointXY(47.75438, 16.549816),
                    new PointXY(47.915512, 16.506475),
                    new PointXY(47.768547, 16.67624)}};
    
    // array of a center points
    PointXY[] centers = clusters[0];
    
    PointXY[][] clustersSorted = Arrays
            // iterate over array of center points
            .stream(centers)
            // for each center point
            .map(center -> Stream.of(center, Arrays
                    // iterate over array of clusters starting from the second row
                    .stream(clusters, 1, clusters.length)
                    // stream over the full array
                    .flatMap(Arrays::stream)
                    // filter nearest points to the current center point
                    .filter(point -> Arrays
                            // iterate over array of center points
                            .stream(centers)
                            // sort by euclidean distance from current point
                            .sorted(Comparator.comparingDouble(centerXY ->
                                    Math.sqrt(Math.pow(centerXY.x - point.x, 2)
                                            + Math.pow(centerXY.y - point.y, 2))))
                            // find nearest center point to the current point
                            .findFirst()
                            // check this center point is the current center point
                            .get() == center)
                    // array of the nearest points to this center point
                    .toArray(PointXY[]::new))
                    // center point + array of its nearest points
                    .flatMap(element -> element instanceof PointXY ?
                            Stream.of((PointXY) element) :
                            Arrays.stream((PointXY[]) element))
                    // sorted cluster
                    .toArray(PointXY[]::new))
            // sorted array of clusters
            .toArray(PointXY[][]::new);
    
    // output
    Arrays.stream(clustersSorted).map(Arrays::toString).forEach(System.out::println);
    
    [23.237633,53.78671]
    [69.15293,17.138134, 47.851738,16.525734, 47.802097,16.689285, 47.946404,16.732542, 47.89601,16.638218, 47.833263,16.478987, 47.88203,16.45793, 47.75438,16.549816, 47.915512,16.506475, 47.768547,16.67624]
    [23.558687,45.70517]
    

    Class PointXY should look like this:

    public static class PointXY {
        double x, y;
    
        public PointXY(double x, double y) {
            this.x = x;
            this.y = y;
        }
    
        @Override
        public String toString() {
            return x + "," + y;
        }
    }
    

提交回复
热议问题