开发者

How can I intersect more than two sets/lists of values?

Here is an example that works in Linqpad. The problem is that I need it to work for more than two words, e.g. searchString = "headboard bed railing". This is a query against an index and instead of "Match Any Word" which I've done, I need it to "Match All Words", where it finds common key values for each of the searched words.

//Match ALL words for categories in index
string searchString = "headboard bed";

List<string> searchList = new List<string>(searchString.Split(' '));

string word1 = searchList[0];
string word2 = searchList[1];

var List1 = (from i in index
            where i.word.ToUpper().Contains(word1)
            select i.category.ID).ToList();         

var List2 = (from i in index
            where i.word.ToUpper().Contains(word2)
            select i.category.ID).ToList();             

//How can I make this work for more than two Lists?
var commonCats = List1.Intersect(List2).ToList();

var category = (from i in index
           from s in commonCats
           where commonCats.Contains(i.category.ID)
           select new 
           {
               MajorCategory = i.category.category1.description,
               MinorCategory = i.category.description,
        开发者_如何学C       Taxable = i.category.taxable,
               Life = i.category.life,
               ID = i.category.ID
           }).Distinct().OrderBy(i => i.MinorCategory);

category.Dump();

Thanks!


Intersection of an intersection is commutative and associative. This means that (A ∩ B ∩ C) = (A ∩ (B ∩ C)) = ((A ∩ B) ∩ C), and rearranging the order of the lists will not change the result. So just apply .Intersect() multiple times:

var commonCats = List1.Intersect(List2).Intersect(List3).ToList();

So, to make your code more general:

var searchList = searchString.Split(' ');

// Change "int" if this is not the type of i.category.ID in the query below.
IEnumerable<int> result = null;

foreach (string word in searchList)
{
    var query = from i in index
                where i.word.ToUpper().Contains(word1)
                select i.category.ID;

    result = (result == null) ? query : result.Intersect(query);
}

if (result == null)
    throw new InvalidOperationException("No words supplied.");

var commonCats = result.ToList();


To build on @cdhowie's answer, why use Intersect? I would think you could make it more efficient by building your query in multiple steps. Something like...

if(string.IsNullOrWhitespace(search))
{
    throw new InvalidOperationException("No word supplied.");
}

var query = index.AsQueryable();

var searchList = searchString.Split(' ');

foreach (string word in searchList)
{
    query = query.Where(i => i.word.ToUpper().Contains(word));
}

var commonCats = query.Select(i => i.category.ID).ToList();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜