Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ find closest coordinates

I'm having a database full of coordinates (x,y), and i wish to find the coordinates closest to a point. (there can be multiple closest to this point)

I've written this 2 LINQ's, but there must be a smarte way, than going through the database two times:

var closestDistance = _context.Coordinates.Min(x =>
                          Math.Sqrt(Math.Pow((point.coordX - x.CoordX), 2) +
                                    Math.Pow((point.coordY- x.CoordY), 2)));
var closest = _context.Coordinates.Where(x=> closestDistance ==
                          Math.Sqrt(Math.Pow((point.coordX - x.CoordX), 2) +
                                    Math.Pow((point.coordY - x.CoordY), 2)));

How can i optimize this?

like image 570
sirius Avatar asked Aug 25 '15 12:08

sirius


2 Answers

  1. You can not calc Math.Sqrt - it does not matter (3 > 2 and 3*3 > 2*2)
  2. You can sort by dist and take first:

var closest = _context.Coordinates.OrderBy(x =>
               Math.Pow((point.coordX - x.CoordX), 2) + Math.Pow((point.WinningCoordY - x.CoordY), 2))
             .First();
  1. Also, replace Math.Pow with multiplication - it will be much faster:

var closest = _context.Coordinates.OrderBy(x =>
               (point.coordX - x.CoordX) * (point.coordX - x.CoordX) + (point.WinningCoordY - x.CoordY) * (point.WinningCoordY - x.CoordY))
             .First();
like image 61
Backs Avatar answered Oct 15 '22 23:10

Backs


You could make use of a group by. Furthermore, you don't have to calculate the square root. You could just use the sum of the squares of the corresponding differences.

Using the GroupBy, you build a sequence of groups, whose key is the distance of the points of each group from the point you are interested in. Then you make an OrderBy of the groups based on the key's value. Last you pick the first group. This contains the points you are looking for.

var closest = _context.Coordinates
                      .GroupBy(x => Math.Pow((point.coordX - x.CoordX), 2) + Math.Pow((point.WinningCoordY - x.CoordY), 2))
                      .OrderBy(x=>x.Key)
                      .First();
like image 45
Christos Avatar answered Oct 15 '22 23:10

Christos