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();
精彩评论