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?
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)
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;
Min will throw an InvalidOperationException if there are no values. You might try something like this. If none are found, closest will be null:
var closest = Airports.GetAllActiveAirports().OrderBy(x => x.GetDistanceTo(n.Profile.Coordinates)).FirstOrDefault();
Related
Suppose I have this table:
Image
Perimeter
a
1
b
1
b
2
d
3
e
1
I want to return the images that have relationship with only ONE perimeter.
The expected result would be images "a,d,e" because image "b" has relationship with perimeter "1" and "2".
The objective is to remove the releated image when I delete the perimeter. But if it is linked to another perimeter, I can't remove it.
How can I write this query with LINQ?
I think it would be something like this:
SELECT "ImageId"
WHERE "PerimeterId" = PerimeterId IN
(
SELECT "ImageId"
GROUP BY "ImageId"
HAVING COUNT("PerimeterId") = 1
)
but I don't know how to convert it to LINQ.
You could use a NOT EXISTS
var query = dbo.Table
.Where(t => !dbo.Table.Any(t2 => t.Image = t.Image && t.Perimeter != t2.Perimeter));
You can easily adapt this to only select the image part. But, if you are coming from SQL, thinking about "Selecting rows" based on a "HAVING()" group calculation, then you will want to look at the .SelectMany() LINQ method. This lets you "combine back together data partitioned into groups". While your needs are to only return "one from each group", it's easy to see where this can be adjusted.
This can be run in the "C# interactive window" of SSDT 2015:
struct imagePerimeter { //this might be whatever object type it is for you...
public string Image { get; set; } //a,b,b,d,e
public int Perimeter { get; set; } //1,1,2,3,1
}
Func<string, int, imagePerimeter> newIP = (i, p) => new imagePerimeter() { Image = i, Perimeter = p };
List<imagePerimeter> results = new List<imagePerimeter>() { {newIP("a",1) }
,{newIP("b",1) }
,{newIP("b",2) }
,{newIP("d",3) }
,{newIP("e",1) } };
Func<imagePerimeter, string> ipImage = (ip) => ip.Image; //the Func's "ipImage" and "newIP" could just be inlined into LINQ, but it helps to see and debug at times IMO.
var imagesWithOnePerimeter = results.GroupBy<imagePerimeter, string>(ipImage) //even in SQL, the "GROUP BY" conceptually comes first, in LINQ, it comes first in code too!
.Select(grp => new { Image = grp.Key, PerimeterCount = grp.Count(), Details = grp }) //there's probably a more technical term, but notice how we "carry forward" the original reference to [grp]
.Where(subTotals => subTotals.PerimeterCount == 1)
.SelectMany(filtered => filtered.Details.AsEnumerable())
.ToList();
This is what I did so far:
class CardDisplayer
{
public int CardSuit;
public int CardValue;
}
List<CardDisplayer> _playerHand;
// Group all cards by the same suit
var _handDuplicates = _playerHand.GroupBy(x => x.CardSuit)
.Select(g => g.ToList())
.ToList();
CardDisplayer _duplicateFound = null;
// And then find all cards with the same value number
for (int i = 0; i < _handDuplicates.Count; i++)
{
var _handReference = _handDuplicates[i];
var _temp = _handReference.GroupBy(x => x.CardValue)
.Where(g => g.Count() > 1)
.Select(g => g.ToList())
.ToList();
// If you find more than one card with the same number
if(_temp.Count > 0)
{
// Take it
_duplicateFound = _temp.First().First();
break;
}
}
What I'm trying to achieve is after get the player's hand I want to find if the player has duplicates in his hand by looking if there is cards with the same suit and the same value.
I tried a lot of things on the internet but I cannot figure out how to get the list of duplicates using LINQ instead write all these lines of code.
Can someone know how to do it please?
Thank you.
you can use the GroupBy method to create a complex key, then use the Any method to find if at least on group has more then 1 object, or Where / FirstOrDefault to find the duplicates
var grouped = _handReference.GroupBy(g => new {suit=g.CardSuit, value=g.CardValue});
var hasDuplicates=grouped.Any(g=>g.Count()>1);
var duplicateList=grouped.Where(g=>g.Count()>1);
var duplicate=grouped.FirstOrDefault(g=>g.Count()>1);
After a while, I found the perfect solution based also on the answers.
// Get the reference for the player hand
List<List<CardDisplayer>> _playerHand = playersSlots[_playerIndex];
// Find in the player's hand duplicates
var _duplicates = _playerHand.GroupBy(x => new { x.CardSuit, x.CardValue })
.Where(x => x.Skip(1).Any())
.SelectMany(g => g)
.Distinct(new CardEqualityComparer()) // Use this only if you want unique results
.ToList();
var _duplicateCard = _duplicates.FirstOrDefault();
If you want unique results you can use a custom CardEqualityComparer class and use it with the Distinct of LINQ
/// <summary>
/// Used to compare if two cards are equals.
/// </summary>
class CardEqualityComparer : IEqualityComparer<CardDisplayer>
{
public bool Equals(CardDisplayer x, CardDisplayer y)
{
// Two items are equal if their keys are equal.
return x.CardSuit == y.CardSuit && x.CardValue == y.CardValue;
}
public int GetHashCode(CardDisplayer obj)
{
return obj.CardSuit.GetHashCode() ^ obj.CardValue.GetHashCode();
}
}
You can find the reference on the web: StackOverflow and DotNetPerls
Thank you, everyone, for the help.
I have collection
Class MyData
{
int f1;
int f2;
int f3;
int f4;
}
var mycollection =List<MyData>();
I need to return object with minimal difference between field f1 and f3.
I tried below query
mycollection.select(obj => obj.f1 - obj.f3).Min();
But it will return the diff number. I need to return the object.
I am kind of struggling to get the object with minimum difference
I also tried this
mycollection.Select(obj => new { MyObject = obj,
diff = obj.MaxTemparature - obj.MinimumTemparature, obj
}).Min(obj => obj.diff);
Try this one
MyData myData = mycollection.OrderBy(o => (o.f1 - o.f3)).First();
You can do below steps to find object by difference F1 - F3.
Calculate difference using .Select() and store it with actual object.
Sort it using .OrderBy() and use difference as a predicate.
Get First record from it.
var result = myData.Select(x => new {diff = Math.Abs(x.F1 - x.F3), obj = x}) //Step 1
.OrderBy(y => y.diff) //Step 2
.FirstOrDefault(); //Step 3
Try it online
Or you can perform subtraction without .Select()
var result = myData.OrderBy(x => Math.Abs(x.F1 - x.F3)).FirstOrDefault();
Try like below.
mycollection.OrderBy(x => Math.Abs(x.f1 - x.f3)).FirstOrDefault();
Order your collection by difference and you want minimal difference so used Math.Abs(x.f1 - x.f3). Then take FirstOrDefault object.
Test it here
I have a web app for calculating the results of a competition:
The competitors attempt x number of activities (each activity is assigned a point value) over several hours.
Their total score is the sum of the 5 highest point values.
I have the following code in my controller. I have tried using .Take(5) in several places but it returns either the top 5 scores only, or the first 5 entered in the table.
The grouping is over several fields as the competitors are awarded prizes by Category (age) and by Gender. I am using a viewmodel named "Game". My most recent unsuccessful code block:
var compdata = from result in db.Results
where result.Complete == true
orderby result.Activity.Value descending
group result by new
{
result.CompetitorId,
result.Competitor.Name,
result.Competitor.Category,
result.Competitor.Gender,
}
into resultsGroup
select new Game
{
CompetitorId = resultsGroup.Key.CompetitorId,
Name = resultsGroup.Key.Name,
Category = resultsGroup.Key.Category,
Gender = resultsGroup.Key.Gender,
Score = resultsGroup.Sum(s => s.Activity.Value)
};
I think you're almost there. When working out the Score value, you need do the Take(5) at that point ... after the grouping. The following isn't the most succinct way to do it but it demonstrates the point based on what you have right now:
Score = resultsGroup.OrderByDescending(s => s.Activity.Value).Take(5).Sum(s => s.Activity.Value)
So that gives something similar to:
var compdata = from result in db.Results
where result.Complete == true
group result by new
{
result.CompetitorId,
result.Competitor.Name,
result.Competitor.Category,
result.Competitor.Gender,
}
into resultsGroup
select new Game
{
CompetitorId = resultsGroup.Key.CompetitorId,
Name = resultsGroup.Key.Name,
Category = resultsGroup.Key.Category,
Gender = resultsGroup.Key.Gender,
Score = resultsGroup.OrderByDescending(s => s.Activity.Value).Take(5).Sum(s => s.Activity.Value)
};
Given a set var battingContribution = IQueryable<Player, Runs> (Basically a list of players and their total batting score) and another set var bowlingContribution = IQueryable<Player, Runs>, how do I pick whose net contribution was the best such that the player whose batting score minus the bowling score results in the highest net total?
Assuming that you have IDictionary<Player, Runs> instead of IQueryable (which doesn't have two type parameters):
// Just to make sure that we don't get exceptions if a player is only in one
// of the two collections -- you might want to handle this case differently
var players = battingContribution.Keys.Intersect(bowlingContribution.Keys);
// Put each player and their performance into what is essentialy a tuple
var performance = players.Select(p =>
new {
Player = p,
Performance = battingContribution[p] - bowlingContribution[p]
});
// Sorting
var orderedPerformance = performance.OrderByDescending(item => item.Performance);
// Selecting best performer
var bestPerformer = orderedPerformance.First().Player;
You can chain these together for terseness if you prefer.
The following works only for Players that are in both Contributions (although I don't know an IQueryable with two type params):
var BestPlayer = (from a in (from bt in battingContribution from bw in BowlingContribution where bt.Player == bw.Player select new { Player = bt.Player, Diff = bt.Runs - bw.Runs)) orderby a.Diff descending select a).First().Player;
MSDN reference to Linq samples see http://msdn.microsoft.com/en-us/vcsharp/aa336746
EDIT - as per comment from OP for completeness:
var BestPlayer = (from a in (from bt in batRuns from bw in bowlRuns where bt.Player == bw.Player select new { Player = bt.Player, Diff = bt.Runs - bw.Runs}) orderby a.Diff descending select a).First();