Reputation: 1550
I have two Lists of Lists:
(1) variants and (2) options.
I need to see if ALL of options exists inside variants (regardless of order).
For Example: in the code below I need to make sure each list of items appears in the variants list - so the list "blue", "red" "green" must appear in the variants list regardless of order
EDIT (clarification): All of the lists inside of "options" must appear in "variants". If one of them fails then the boolean must return false.
I setup a LINQ condition but I'm not sure why its not working. Any help would be appreciated.
//TEST 1
List<List<string>> variants = new List<List<string>>();
variants.Add(new List<string> {"cars", "boats", "planes"});
variants.Add(new List<string> {"money", "trees", "plants"});
variants.Add(new List<string> {"green", "blue", "red" });
variants.Add(new List<string> {"kid", "adult", "senior"});
variants.Add(new List<string> {"tax", "insurance", "salary"});
List<List<string>> options = new List<List<string>>();
options.Add(new List<string> { "senior", "adult", "kid" });
options.Add(new List<string> { "blue", "red", "green"});
options.Add(new List<string> {"money", "trees", "plants"});
bool exists = variants.Any(a => options.Any(b => b.SequenceEqual(a.OrderBy(x => x))));
Console.WriteLine(exists);
// The result should be TRUE even though the order of "senior", "adult" and "kid"
// is different and that the order of listed items is different
//TEST 2
List<List<string>> options2 = new List<List<string>>();
options2.Add(new List<string> { "senior", "adult", "kid" });
options2.Add(new List<string> { "orange", "red", "green"});
options2.Add(new List<string> {"money", "trees", "plants"});
exists = variants.Any(a => options2.Any(b => b.SequenceEqual(a.OrderBy(x => x))));
Console.WriteLine(exists);
// The result should be FALSE. All listed options are TRUE except that the 2nd list has
// "orange" which doesn't appear in the variants list.
//TEST 3
List<List<string>> options3 = new List<List<string>>();
options3.Add(new List<string> { "senior", "red", "adult" });
options3.Add(new List<string> { "blue", "kid", "green"});
options3.Add(new List<string> {"money", "trees", "plants"});
exists = variants.Any(a => options3.Any(b => b.SequenceEqual(a.OrderBy(x => x))));
Console.WriteLine(exists);
// The result should be FALSE. All of the items actually exist in the variant list,
// but "senior", "kid", and "adult" do not appear together within a list of variants.
Upvotes: 3
Views: 1435
Reputation: 38179
You can build a HashSet
for each variants list and then check for each options list at least one variant set contains all the options:
List<HashSet<string>> variantSets = variants.Select(vl => new HashSet<string>(vl)).ToList();
bool allIncluded = options.All(ol => variantSets.Any(vs => ol.All(vs.Contains)));
Upvotes: 3
Reputation: 763
Your code works so far, but both lists should be sorted within the comparison.
before:
bool exists = variants.Any(a => options.Any(b => b.SequenceEqual(a.OrderBy(x => x))));
fixed:
bool exists = options.All(a => variants.Any(b => b.OrderBy(x => x).SequenceEqual(a.OrderBy(x => x))));
Upvotes: 2
Reputation: 26213
I'd suggest you use HashSet<T>
rather than List<T>
for the options / variants, as you have set semantics here rather than list semantics: options can only appear once & the order isn't important.
For example:
var variants = new List<HashSet<string>>();
variants.Add(new HashSet<string> {"cars", "boats", "planes"});
variants.Add(new HashSet<string> {"money", "trees", "plants"});
variants.Add(new HashSet<string> {"green", "blue", "red" });
variants.Add(new HashSet<string> {"kid", "adult", "senior"});
variants.Add(new HashSet<string> {"tax", "insurance", "salary"});
And your check is backwards: you want to check if all options match any of the variants. So you need to start with options. HashSet<T>
has a method to check if the sets are equal, so you can use this:
bool exists = options.All(option => variants.Any(option.SetEquals));
Upvotes: 3