Reputation: 15609
I have a block of code that checks a List
for derived types and then adds to first instance to another List
.
var bacon = new List<Bacon>(); // A list of all bacon products
var selectedBacon = new List<Bacon>();
var smokey= bacon.FirstOrDefault(x => x is Smokey);
if (smokey != null)
{
selectedBacon.Add(smokey);
}
var rasher = bacon.FirstOrDefault(x => x is Rasher);
if (rasher != null)
{
selectedBacon.Add(rasher);
}
This method is starting to get quite long as the amount of types increase.
I would like to be able to refactor this into a Linq statement that can check for multiples types and adds the first item to a new List
. Sort of like a whitelist approach. Any ideas as to how I can do this?
Upvotes: 2
Views: 101
Reputation: 56429
You can do the following (if there's typo's, I blame the sidetracking thought of crispy bacon as we near lunch time):
var types = new List<Type>
{
typeof(Smokey),
typeof(Rasher),
typeof(Danish)
};
As mentioned in comments, for every item in your bacon list, you want the first matching corresponding type from types:
List<Type> selectedBaconTypes = bacon
.Select(b => types.FirstOrDefault(t => b.GetType().Equals(t.GetType())))
.Where(b => b != null)
.ToList();
Upvotes: 4
Reputation: 111820
Mmmh... Bacon...
var types = new List<Type>
{
typeof(Smokey),
typeof(Rasher),
typeof(Danish)
};
var bacon = new List<Bacon>();
// ..
var selectedBacon = new List<Bacon>();
if (types.Count != 0)
{
// We clone it
var types2 = types.ToList();
foreach (var b in bacon)
{
var btype = b.GetType();
// A bacon could be of multiple "types" thanks to subclassing
while (true)
{
// The IsAssignableFrom is equivalent to the is operator
int ix = types.FindIndex(x => x.IsAssignableFrom(btype));
if (ix != -1)
{
selectedBacon.Add(b);
types2.RemoveAt(ix);
}
else
{
break;
}
}
if (types2.Count == 0)
{
break;
}
}
}
Note the use of IsAssignableFrom
instead of using GetType()
. In this way, you can have a class SmokeyPlusCheese : Smokey
.
Upvotes: 1
Reputation: 21
Do you only want the first occurrence of each type? If so I'd imagine you could do something like this:
var types = new List<Type>
{
typeof(Smokey),
typeof(Rasher),
typeof(Danish)
};
foreach(var b in bacon) {
if (types.Any(t => b.GetType() == t)) {
selectedBacon.Add(b);
types.Remove(b.GetType());
}
if (types.Count == 0) {
break;
}
}
Hope it helps!
EDIT: Fixed compilation issues. This should work as long as there isn't sub-sub classes of Bacon.
Upvotes: 0
Reputation: 37760
Something like this:
var bacon = new List<Bacon>();
bacon
.GroupBy(_ => _.GetType())
.Select(_ => _.FirstOrDefault())
.ToList();
Upvotes: 0