Reputation: 4247
I have the following objects:
public interface ITray
{
int OrderNo {get; set;}
IEnumerable<ITrayItem> TrayItems {get;}
}
public interface ITrayItem
{
int Aisle {get; set;}
}
Now, I have two List objects,
List<ITray> selectedTrays
List<ITray> poolTrays
What I am trying to do is for each element in poolTrays, I want to compare the Aisles that are in the list of selected trays. If all of the Aisles match, I want to add it to a list of trays to return. I'm just tying myself in knots a bit trying to get the linq working with the querying of a property of a collection inside a list and returning the items in the list that match.
This is what I have at the moment:
List<int> selectedAisles = (from tray in selectedTrays
from item in tray.TrayItems
select item.Aisle).Distinct().ToList()
List<ITray> trayswithMatchingAisles =
(from t in poolTrays
from item in t.TrayItems
where selectedAisles.Contains(item.Aisle)
select t).ToList();
So, if I have selected Trays A, B, C with aisles in brackets A[1,2,3] B[4,5,6] c[7,8,9]
then a poolTray with TrayItems in aisles [7,9] should return successfully, but a pool tray with TrayItems [7,8,9,10] should not be returned in the list.
At the moment, I am passing in (just) [7,9] in my poolTray list, and 2 instances of it are returned in my Linq query
Upvotes: 3
Views: 1071
Reputation: 63387
var result = poolTrays.Where(x => selectedTrays.Any(z=>z.TrayItems.Select(y => y.Aisle)
.Intersect(x.TrayItems.Select(k => k.Aisle))
.Count() == x.TrayItems.Count()));
Upvotes: 2
Reputation: 149108
Something like this should work:
List<int> selectedAisles =
(from tray in selectedTrays
from item in tray.TrayItems
select item.Aisle)
.Distinct().ToList();
List<ITray> trayswithMatchingAisles =
(from t in poolTrays
where t.TrayItems.Select(i => i.Aisle)
.All(a => selectedAisles.Contains(a))
select t)
.ToList();
But this can be simplified to:
List<ITray> trayswithMatchingAisles =
(from t in poolTrays
where t.TrayItems.Select(i => i.Aisle)
.All(a => selectedTrays
.SelectMany(s => s.TrayItems)
.Select(i => i.Aisle)
.Contains(a))
select t)
.ToList();
Or this:
List<ITray> trayswithMatchingAisles = poolTrays
.Where(t => t.TrayItems
.Select(i => i.Aisle)
.All(a => selectedTrays
.SelectMany(s => s.TrayItems)
.Select(i => i.Aisle)
.Contains(a)))
.ToList();
Upvotes: 2
Reputation: 13124
I think you need to use the "SelectMany" extension, this is to flat queries that return lists of lists.
For example:
var distinctSelectedItems = selectedTrays.SelectMany(t => t.TrayItems).Select(ti => ti.Aisle).Distinct();
bool success = poolTrays.SelectMany(t => t.TrayItems).All(ti => distinctSelectedItems.Contains(ti.Aisle));
You can also create a HashSet, in order to have O(1) performance, instead of O(n) for the List.Contains.
var distinctSelectedItems = new HashSet<int>(selectedTrays.SelectMany(t => t.TrayItems).Select(ti => ti.Aisle));
bool success = poolTrays.SelectMany(t => t.TrayItems).All(ti => distinctSelectedItems.Contains(ti.Aisle));
Good luck.
Upvotes: 2