Reputation: 2323
I have a static set of categories, and an incoming list of items that are in various categories. I want to get the first item that matches the best category, and if none is found, get the first item that matches the next-best category, etc. until I get to a default category.
I tried putting my categories in an IEnumerable and doing a Contains()
on it to see if my incoming items match a category, and stopping on the first match. But I can't control the match order: if the category list is ordered by priority [best, OK, default]
, the first input item to match anything in the category list wins. So if my first input item matches OK
, and the second input item matches Best
, then I'll stop before I get the Best
match.
Right now I run Where()
over the item list, and if the result is null I run a second Where()
, etc. I'd like to know if there's a more concise (or more LINQ-idiomatic) way to write this:
public MyVM getVM( IEnumerable<Entities.Foo> foos )
{
Entities.Foo foo = null;
MyVM myVM = null;
if ( entity.IsBar )
{
foo = foos.Where( f => f.FooCatId == FooCategories.BestCat ).FirstOrDefault();
}
// no foos are BestCat, look for OkCat
if ( foo == null )
{
foo = foos.Where( f => f.FooCatId == FooCategories.OkCat ).FirstOrDefault();
}
// no foos are OkCat, look for DefaultCat
if ( foo == null )
{
foo = foos.Where( f => f.FooCatId == FooCategories.DefaultCat ).FirstOrDefault();
}
if ( foo != null )
{
myVM = new MyVM() { Name = foo.Name };
}
return myVM;
}
public enum FooCategories
{
DefaultCat,
SomeCat,
AnotherCat,
OkCat,
BestCat,
BadCat
}
Upvotes: 1
Views: 1465
Reputation: 1500245
There's certainly a more concise way of doing it, in two ways:
FirstOrDefault
which takes a predicateI'm going to ignore your IsBar
check for now, because I don't understand how that fits in... but the rest would be:
var foo = foos.FirstOrDefault(f => f.FooCatId == FooCategories.BestCat)
?? foos.FirstOrDefault(f => f.FooCatId == FooCategories.OkCat)
?? foos.FirstOrDefault(f => f.FooCatId == FooCategories.DefaultCat);
Another option would be to change your enum order so that you could just find the cat with the best category - either by using OrderByDescending(f => f.FooCatId)
or by using MaxBy
from MoreLINQ. You'd also then need to check that the resulting cat isn't a bad cat, etc, so it might not be much of a win - but MaxBy
would at least be more efficient, by only going through the list once.
Upvotes: 4