Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda/LINQ Select Minimum

I'm writing a function using the .NET GeoCoordinate class. We have an Airport class and a City class, both of which define their own GeoCoordinate.

I need to select the nearest airport relative to the city, and I am trying to do so using the GetDistanceTo() method.

What I have right now looks something like this:

Airport a = Airports.GetAllActiveAirports().Min(this.Coordinates.GetDistanceTo(n.Profile.Coordinates));

Another (working) function that retrieves a list of nearest airports by distance uses:

List<Airports> airports = Airports.GetAllActiveAirports();
var nearby = 
    from a in airports
    where this.Coordinates.GetDistanceTo(a.Profile.Coordinates) > d
    select a;
foreach(Airport a in nearby)
{ 
    airports.Remove(a); 
}

I've seen examples of doing things like this in a single line with LINQ & lambdas, but I'm not entirely sure how to execute this one...any pointers?

like image 402
mikedugan Avatar asked Jan 01 '14 04:01

mikedugan


2 Answers

If I get your question, this line gets the minimum distance from Coordinates to an active airport.

Airports.GetAllActiveAirports().Min(_ => Coordinates.GetDistanceTo(_.Profile.Coordinates))

If you want the airport in question then:

var airports = Airports.GetAllActiveAirports();
var closest = airports.First(_ => Coordinates.GetDistanceTo(_.Profile.Coordinates) == airports.Min(_ => Coordinates.GetDistanceTo(_.Profile.Coordinates)))

You don't have to keep it in one line... Visual Studio won't run out of space.

An even better option, without getting the minimum in every iteration would be:

var airports = Airports.GetAllActiveAirports();
var minDistance = airports.Min(_ => Coordinates.GetDistanceTo(_.Profile.Coordinates))
var closest = airports.First(_ => Coordinates.GetDistanceTo(_.Profile.Coordinates) == minDistance)
like image 52
i3arnon Avatar answered Nov 15 '22 04:11

i3arnon


The accepted answer causes 2 calls to GetDistance for each airport. Here's how you can do it in a single pass:

var closestAirport = Airports.GetAllActiveAirports()
    .Select(x => new {
        Airport = x, 
        Distance = this.Coordinates.GetDistanceTo(x.Profile.Coordinates)})
    .Aggregate((a1, a2) => a1.Distance < a2.Distance ? a1 : a2)
    .Airport;
like image 40
Eren Ersönmez Avatar answered Nov 15 '22 04:11

Eren Ersönmez