Colin Bacon
Colin Bacon

Reputation: 15609

Check if a List contains specific types (multiple)

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.

Question

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

Answers (4)

Mathew Thompson
Mathew Thompson

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

xanatos
xanatos

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

Jo&#227;o Vargas
Jo&#227;o Vargas

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

Dennis
Dennis

Reputation: 37760

Something like this:

        var bacon = new List<Bacon>();

        bacon
            .GroupBy(_ => _.GetType())
            .Select(_ => _.FirstOrDefault())
            .ToList();

Upvotes: 0

Related Questions