Reputation: 11
I have a class like this
public class ValueGroup
{
public string Name { get; set; }
public List<Value> Values { get; set; }
}
public class Value
{
public int RealValue { get; set; }
public bool IsFavourite { get; set;
}
And a list of some items
var valueList = new List<ValueGroup>
{
new ValueGroup
{
Name = "1st Group",
Values = new List<Value>
{
new Value
{
RealValue = 6,
IsFavourite = false
},
new Value
{
RealValue = 2,
IsFavourite = true
},
new Value
{
RealValue = 4,
IsFavourite = false
}
}
},
new ValueGroup
{
Name = "2nd Group",
Values = new List<Value>
{
new Value
{
RealValue = 7,
IsFavourite = false
},
new Value
{
RealValue = 3,
IsFavourite = true
},
new Value
{
RealValue = 8,
IsFavourite = true
}
}
},
new ValueGroup
{
Name = "3rd Group",
Values = new List<Value>
{
new Value
{
RealValue = 9,
IsFavourite = false
},
new Value
{
RealValue = 1,
IsFavourite = true
},
new Value
{
RealValue = 5,
IsFavourite = false
}
}
}
}
So, now I would like to select the value group, which has the highest RealValue paired with an IsFavourit == true in its nested ValueList. So in this case, I want to select the 2nd group (the 3rd one has a bigger value, but this is not an isFavourite). Is there a chance to realize this with LINQ? Thanks for comments!
Upvotes: 1
Views: 541
Reputation: 30454
So basically, all you have to do, is for every ValueGroup
extract the Highest Favorite RealValue while remembering the ValueGroup. Result: combinations of [Highest Favorite RealValue, ValueGroup]
From these combinations find the one with the Highest RealValue.
The problem with Max and MaxBy is that they don't work well with empty collections: what is the highest RealValue is all are not IsFavorite?
Therefore I'll use OrderBy and FirstOrDefault, so I'm always certain that I get a value, even if all are not IsFavorite
IEnumerable<ValueGroup> valueGroups = ...
ValueGroup valueGroupWithLargestFavoriteRealValue = valueGroups
.Select(valueGroup => new
{
HighestFavoriteRealValue = valueGroup.Values
.Where(value => value.IsFavorite)
.Select(value => value.RealValue)
.OrderByDescending(realValue => realValue)
.FirstOrDefault(),
ValueGroup = valueGroup,
})
.OrderByDescending(combination => combination.HighestFavoriteRealValue)
.Select(combination => combination.ValueGroup)
.FirstOrDefault();
In words: from every valueGroup
in your input sequence of valueGroups
make one combination element that has two properties:
To calculate the HighesFavoriteValue of this valueGroup, take all Values of this valueGroup, and keep only those that are IsFavorite. From the remaining values take the RealValue. Result: a bunch of realValues that all has IsFavorite. Order this bunch in descending order and take the first or default one. If there were no IsFavorites you get zero, otherwise you have the Highest Favorite real value.
Order this sequence of combinations [HighestFavoriteValue, ValueGroup] by descending value of HighestFavoriteValue. From every combination in this sorted sequence select the ValueGroup. From the resulting sequence of ValueGroups take the first, or the default if there is no ValueGroup left.
Upvotes: 0
Reputation: 17492
If you want to select the whole ValueGroup
object, use MaxBy
.
ValueGroup? largestValueGroup = valueList
.Where(vg => vg.Values.Any(v => v.IsFavourite))
.MaxBy(vg => vg.Values
.Where(v => v.IsFavourite)
.Max(v => v.RealValue));
Console.WriteLine(largestValueGroup?.Name);
// 2nd Group
How this works:
The first Where
only allows ValueGroups
through that have at least one Values
entry where IsFavourite
is true.
MaxBy
starts to evaluate all the remaining groups. For each group:
Filter out any Value
which is not a favorite.
Get the max of the resulting Value entries (remember, we're still inside of an individual group) and get the maximum value.
Normally, you'd get a InvalidOperationException
if you pass an empty sequence to Max()
(such as if there were no Value
entries that were favorites), but that's what the very first Where
does (before the MaxBy
). When you run Max
, you know for certain that at least one Value
entry is a favorite.
The MaxBy
now has evaluated each source ValueGroup
into a number, and finds the maximum, and returns the matching source object.
However, if MaxBy
got an empty collection, such is the case when ALL ValueGroups
did not contain a favorite, then MaxBy
itself will return null.
Upvotes: 4