Reputation: 85
Given the following class structure need to extract various members based on custom property value:
class Item{
public Item(int position, Image image)
{
Position = position;
Image = image;
}
public int Position { get; set; }
public Image Image { get; set; }
public int Quality { get; set; }
}
class Items : List<Item> {}
class ConsolidatedItems : List<Items> {}
How do I get a list of "best" Items based on Quality joined by Position (in other words group items where Position is the same):
Input
Items1:
Item1: 1, ImageBinary, 100
Item2: 2, ImageBinary, 98
Item3: 3, ImageBinary, 45
Item4: 4, ImageBinary, 66
Items2:
Item1: 1, ImageBinary, 76
Item2: 2, ImageBinary, 80
Item4: 4, ImageBinary, 33
Items3:
Item1: 2, ImageBinary, 76
Item2: 3, ImageBinary, 80
Item4: 4, ImageBinary, 90
Output
BestItems:
Item1: 1, ImageBinary, 100 (from Items1)
Item2: 2, ImageBinary, 98 (from Items1)
Item3: 3, ImageBinary, 80 (from Items3)
Item4: 4, ImageBinary, 90 (from Items4)
Upvotes: 0
Views: 2054
Reputation: 21487
Assuming that the Position
is already filled in, then you can use SelectMany to flatten your ConsolidatedItems, group them by the position, order the groups by position, and then choose the best quality from each group:
var bestItems = data
.SelectMany(x => x)
.GroupBy(x => x.Position)
.OrderBy(x => x.Key)
.Select(x => x.OrderByDescending(i=>i.Quality).First());
Upvotes: 0
Reputation: 876
var best = data
.GroupBy(x => x.Position)
.Select(x => x.Aggregate(
(result, item) => item.Quality > result.Quality ? item : result)
);
data
is a collection of Item
using System.Linq;
best
is an IEnumerable
you can convert it to a list or array if you wish using ToList()
or ToArray()
Edit based on the discussion:
In case your data
is an instance of ConsolidatedItems
, i.e. a nested collection, you need to flatten it first using SelectMany
:
var best = data
.SelectMany(x => x)
.GroupBy(x => x.Position)
.Select(x => x.Aggregate(
(result, item) => item.Quality > result.Quality ? item : result)
);
data
contains your entriesGroupBy
creates a collection with key
being the property or computed value you selected for grouping. You can of course iterate over all its items which will come handy in the next steps.Select
will compute a new entity for each group -- the one with the best quality.Aggregate
is perhaps the most difficult function here. It iterates over the members of a group and keeps one element as the result. The result is initialized with the first element. Then Aggregate
moves on over the whole collection and compares each item against the currently best result. At the end it returns the result with the best element.Please note that your collection classes are not designed well. Have a look here why not to inherit form List.
Upvotes: 2