当您有一个复杂的对象结构时,如何将几个嵌套循环转换为lambda或linq

本文关键字:几个 嵌套循环 转换 linq lambda 复杂 有一个 对象 结构 | 更新日期: 2023-09-27 18:05:07

在尝试将多个嵌套循环转换为lambda或linq表达式时,我遇到了麻烦。我想我很难理解在使用。all或。contains方法时如何正确访问属性。无论如何,帮助是非常感激的。(我已经读了一些关于这个主题的其他帖子,但我仍然在努力使它工作。)

下面是这些类的样子:

public class RecipeSearch
{
    public List<Recipe> Recipe { get; set; }
    public List<Meal> MealSettings { get; set; }
    public List<Ingredient> MainIngredient { get; set; }
}
public class Meal
{
    public int Id { get; set; }
    public bool Value { get; set; }
    public string DisplayName { get; set; }
}
public class MainIngredient
{
    public int Id { get; set; }
    public bool Value { get; set; }
    public string DisplayName { get; set; }
}

下面是嵌套循环:

IEnumerable<Recipe> recipeList = dbContext.Recipes
                .OrderBy(r => r.name)
                .Where(r => r.name.Contains(name) || string.IsNullOrEmpty(name))
                .ToList();
//Model object is of type RecipeSearch
            IEnumerable<Meal> selectedMeals = model.MealSettings.Where(x => x.Value == true);
            IEnumerable<MainIngredient> selectedIngredients = model.MainIngredient.Where(x => x.Value == true);
    foreach (var selected in recipeList) //loop through the master list 
    {
        foreach (var item in selectedMeals) //loop through selected meal categories 
        {
            if (selected.mealCategoryId == item.Id) //passed the meal category check (i.e. it exists)
            {
                foreach (var ingredient in selectedIngredients) // selected master ingredients
                {
                    if (selected.Ingredients.Any(x => x.SubCategory.mainCategoryid == ingredient.Id))
                    {
                        recipe.Recipe.Add(selected);
                        break;
                    }
                }
            }
        }
    }

我想应该注意到循环完全按照预期工作。我只是觉得lambda/linq更容易读懂。

编辑:以下是其他对象:

    public partial class Recipe
    {
        public Recipe()
        {
            Directions = new HashSet<Direction>();
            Images = new HashSet<Image>();
            Ingredients = new HashSet<Ingredient>();
            Nutritions = new HashSet<Nutrition>();
            Ratings = new HashSet<Rating>();
        }
        public int recipeId { get; set; }
//Removed other properties that are not relevant
        public virtual ICollection<Ingredient> Ingredients { get; set; }
        public virtual MealCategory MealCategory { get; set; }
        public virtual RecipeStatus RecipeStatus { get; set; }
    }
public partial class Ingredient
{
    public int ingredientId { get; set; }
    public int? recipeId { get; set; }
    public int? subCategoryId { get; set; }
    public int measurementId { get; set; }
    public int amount { get; set; }
    public virtual Recipe Recipe { get; set; }
    public virtual SubCategory SubCategory { get; set; }
    public virtual Measurement Measurement { get; set; }
}
public partial class SubCategory
{
    public SubCategory()
    {
        Ingredients = new HashSet<Ingredient>();
    }
    public int subCategoryId { get; set; }
    [Required]
    [StringLength(255)]
    public string name { get; set; }
    public int? mainCategoryid { get; set; }
    public virtual ICollection<Ingredient> Ingredients { get; set; }
    public virtual Maincategory Maincategory { get; set; }
}

当您有一个复杂的对象结构时,如何将几个嵌套循环转换为lambda或linq

这样行吗?

var query = from selected in receipeList
            join item in selectedMeals on selected.MealCategoryId equals item.Id
            where selected.Ingredients.Select(x => x.SubCategory.mainCategoryid.Value)
              .Intersect(selectedIngredients.Select(s => s.Id)).Count() > 0
            select selected;

foreach(var sel in query)
    recipe.Recipe.Add(sel);

我看不出你是从哪里得到recipe.Recipe的。

基本上是为了帮助你把它转换成linq并根据你的需要进行调整:

:

foreach (var selected in recipeList) //loop through the master list 
    {
        foreach (var item in selectedMeals) //loop through selected meal categories 
        {
            if (selected.mealCategoryId == item.Id) //passed the meal category check (i.e. it exists)
            {
            }
        }
    }

转换成如下连接:

from selected in receipeList
join item in selectedMeals on selected.MealCategoryId equals item.Id

同样,这些行:

if (selected.Ingredients.Any(x => x.SubCategory.mainCategoryid == ingredient.Id))
{
    recipe.Recipe.Add(selected);
    break;
}

可译为:

where selected.Ingredients.Select(x => x.SubCategory.mainCategoryid.Value)
              .Intersect(selectedIngredients.Select(s => s.Id)).Count() > 0
select selected;
//and then
foreach(var sel in query)
    recipe.Recipe.Add(sel);

注意以下部分,

IEnumerable<Recipe> recipeList = dbContext.Recipes
            .OrderBy(r => r.name)
            .Where(r => r.name.Contains(name) || string.IsNullOrEmpty(name))
            .ToList();

这里有2种气味:首先,您应该交换or条件来检查String。首先是IsNullOrEmpty,然后其次,将where放在order前面,以减少需要订购的项目。

IEnumerable<Recipe> recipeList = dbContext.Recipes               
            .Where(r => string.IsNullOrEmpty(name) || r.name.Contains(name))
            .OrderBy(r => r.name)
            .ToList();

根据ItemCount的不同,这可能会给你一些"boost"