LINQ,其中第三个嵌套子元素的属性值等于什么?

Sve*_*ang 5 c# linq collections

我无法获得这个LINQ在哪里返回任何结果,我有几个这样的类:

public class RestaurantMenu
{
    public List<MenuItem> MenuItems { get; set; }
}

public class MenuItem
{
    public decimal Price { get; set; }
    public List<FoodItem> FoodItems { get; set; }
}

public class FoodItem
{
    public string Label { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

给定一个列表RestaurantMenu,我试图返回任何匹配的结果,其中餐厅菜单的菜单项的食品项目的标签匹配列表中的所有字符串.基本上,你输入你想要吃的食物,它应该返回任何你想要吃的东西的餐馆.它应该支持多个字符串,但我甚至无法匹配一个字符串.

假设如下:

List<RestaurantMenu> allRestaurantMenus = /blah;
List<string> labelOfFoodsDesired = /blah;
Run Code Online (Sandbox Code Playgroud)

我尝试通过链接表达式来实现它:

IQueryable<RestaurantMenu> query = allRestaurantMenus.AsQueryable();

        foreach (string foodItem in labelOfFoodItemsDesired)
        {
            query = query.Where(x => x.MenuItems.Any(y => y.FoodItems.Select(z => z.Label).Contains(foodItem)));
        }

        List<RestaurantMenu> matchingRestaurantMenus = query.ToList();
Run Code Online (Sandbox Code Playgroud)

但它始终没有返回任何结果,即使通过调试我确信有匹配.我该怎么写这个查询?

Ser*_*kiy 3

allRestaurantMenus.Where(m => 
    m.MenuItems.Any(mi => 
        !labelOfFoodsDesired.Except(mi.FoodItems.Select(fi => fi.Label)).Any()))
Run Code Online (Sandbox Code Playgroud)

它是如何工作的:我们正在过滤至少有一个菜单项以及您传递的所有标签的菜单。与Enumerable.Except

!labelOfFoodsDesired.Except(mi.FoodItems.Select(fi => fi.Label)).Any()
Run Code Online (Sandbox Code Playgroud)

我们在所需标签和食品的所有标签之间设置差异。如果食品标签中存在所有所需标签,则设置将为空。

更新:如果您应该检查任何菜单项(不是单个菜单项),那么查询将如下所示

allRestaurantMenus.Where(m => 
    !labelOfFoodsDesired.Except(
       m.MenuItems.SelectMany(mi => mi.FoodItems.Select(fi => fi.Label))).Any())
Run Code Online (Sandbox Code Playgroud)

工作原理:方法与上面相同,但您应该检查所有菜单项的所有标签。这是通过Enumerable.SelectMany完成的,它将菜单项的集合扁平化为所有标签的集合。然后,如上所述,您可以在所需标签和所有菜单项的所有标签之间建立差异集。如果设置为空,则菜单满足您的条件。

测试:给出以下菜单

List<RestaurantMenu> allRestaurantMenus = new List<RestaurantMenu> {
    new RestaurantMenu {
            MenuItems = new List<MenuItem> {
                new MenuItem {
                    FoodItems = new List<FoodItem> {
                        new FoodItem { Label = "Chocolate" },
                        new FoodItem { Label = "Water" }
                    }
                },
                new MenuItem {
                    FoodItems = new List<FoodItem> {
                        new FoodItem { Label = "Egg" },
                        new FoodItem { Label = "Ketchup" }
                    }
                }
            }
    },
    new RestaurantMenu {
        MenuItems = new List<MenuItem> {
                new MenuItem {
                    FoodItems = new List<FoodItem> {
                        new FoodItem { Label = "Water" }
                    }
                },
                new MenuItem {
                    FoodItems = new List<FoodItem> {
                        new FoodItem { Label = "Banana" },
                        new FoodItem { Label = "Peach" }
                    }
                }
           }
      }
 };
Run Code Online (Sandbox Code Playgroud)

并遵循所需的标签

List<string> labelOfFoodsDesired = new List<string>
{
    "Water", "Banana"
};
Run Code Online (Sandbox Code Playgroud)

上面的查询会将菜单展平为所有标签的序列:

{ "Chocolate", "Water", "Egg", "Ketchup" }
{ "Water", "Banana", "Peach" }
Run Code Online (Sandbox Code Playgroud)

然后它将在所需标签和扁平化结果之间建立差异:

{ "Banana" }
{ }
Run Code Online (Sandbox Code Playgroud)

因此第二个结果为空(菜单中存在所有所需的标签),只有第二个菜单会匹配。