Finding the closest points in an array

2019-08-25 11:40发布

问题:

I am trying to find not just the closest point, but the 3 closest points in an array of 5 object points. I have tried several experiments using just a distance(d) variable for each point. But I cannot figure out how to iterate through each point, compare it to the other points using the Pythagorean Theorem/Distance formula, and then find the closest 3. If the array has 5 points, I am guessing I need to store the results of each iteration in an array with a distance (d) value, sort by the distance value, and then remove the last item in the new array. Here is the array:

 var points = [
   { id: 1, x: 0.0, y: 0.0 },
   { id: 2, x: 10.1, y: -10.1 },
   { id: 3, x: -12.2, y: 12.2 },
   { id: 4, x: 38.3, y: 38.3 },
   { id: 5, x: 79.0, y: 179.0 },
 ]; 

I have a function that finds the closest 3 points based on a d key value for distance:

 function closest(n, { id, d }) {
    return points
      .filter(o => o.id !== id)
      .sort((a, b) => Math.abs(a.d - d) - Math.abs(b.d - d))
      .slice(0, n);
 };

And I have a way to apply this function and console log the results so that it prints "ID: 1stClosest, 2ndClosest, 3rdClosest":

 result = points.map(o => 
   Object.assign({}, o, { closest: closest(3, o) }));

 result.forEach((item) => {
   console.log(item.id + ': ' + item.closest[0].id + ', ' + item.closest[1].id + ', ' + item.closest[2].id);}); 

Now, I am just trying to iterate through each point, apply the distance formula to get the d: value for each point comparison, push it to a new array, I assume and then apply the above portions (result and closest functions). How can I do this? Here's what I have so far:

 points.forEach((item) => {
  var newArray = [item];
  var pt = null;
  var d = null;
  for (var i = 0; i < points.length; i = i + 1) {
      //compare this point with all of the other points
      for (var j = i + 1; j < points.length; j = j + 1) {
          //compute distance
          var curr = Math.sqrt(Math.pow(points[i][0] - points[j][0], 2) + Math.pow(points[i][1] - points[j][1], 2));
      //get the distance between each point and push to a new array
          if (d === null || curr < d) {
            o = points.id[i];
            pt = points.id[j];
            d = curr;
          }
       }
     }
  newArray.push = {
   "id": o,
   "pt": pt,
   "d": d
  };
  console.log(newArray);
});

回答1:

If I understand correctly, this is similar to the closest pair of points problem. One (intuitive, but perhaps inefficient) approach is to simply brute force the items in the collection. That is, for two points, you use two for loops. For three points, then, you could use three nested loops. Then, you'd find the maximum "closeness." I'm not sure how you want to define closeness, but I figure the sum of the distances from A to B, B to C, and C to A would work well. Testing every enumeration of the point groupings for minimum "distance" would result in the closest pairing.

So, I'm not sure where your other functions would come into play. The larger problem is finding how to determine "closest," so calling a function to do a subproblem that is the bigger problem doesn't check out.

If you somehow want the three closest groups of points, then you would need to keep track of each pairing's distance and determine how your want to keep them distinct from each other. I.e., do you want to allow the same point to be in another group of points?