How to use LINQ to find all items in list which have the most members in another list?

Given:

class Item {
    public int[] SomeMembers { get; set; }
}

var items = new []
{
    new Item { SomeMembers = new [] { 1, 2 } }, //0
    new Item { SomeMembers = new [] { 1, 2 } }, //1
    new Item { SomeMembers = new [] { 1 } }     //2
}

var secondList = new int[] { 1, 2, 3 };

I need to find all the Items in items with the most of it's SomeMembers occurring in secondList.

In the example above I would expect Items 0 and 1 to be returned but not 2.

I know I could do it with things like loops or Contains() but it seems there must be a more elegant or efficient way?

Jon Skeet
people
quotationmark

This can be written pretty easily:

var result = items.Where(item => item.SomeMembers.Count(secondList.Contains) * 2
                                         >= item.SomeMembers.Length);

Or possibly (I can never guess whether method group conversions will work):

var result = items.Where(item => item.SomeMembers.Count(x => secondList.Contains(x)) * 2
                                         >= item.SomeMembers.Length);

Or to pull it out:

Func<int, bool> inSecondList = secondList.Contains;
var result = items.Where(item => item.SomeMembers.Count(inSecondList) * 2
                                         >= item.SomeMembers.Length);

If secondList becomes large, you should consider using a HashSet<int> instead.

EDIT: To avoid evaluating SomeMembers twice, you could create an extension method:

public static bool MajoritySatisfied<T>(this IEnumerable<T> source,
                                        Func<T, bool> condition)
{
    int total = 0, satisfied = 0;
    foreach (T item in source)
    {
        total++;
        if (condition(item))
        {
            satisfied++;
        }
    }
    return satisfied * 2 >= total;
}

Then:

var result = items.Where(item => item.MajoritySatisfied(secondList.Contains));

people

See more on this question at Stackoverflow