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

时间:2014-05-26 15:14:17

标签: c# linq loops lambda

我在尝试将多个嵌套循环转换为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; }
}

2 个答案:

答案 0 :(得分:3)

这会有用吗?

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);

答案 1 :(得分:0)

请注意以下部分,

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

这里有两件事: 首先,你应该先交换or-condition来检查String.IsNullOrEmpty,然后 第二个把orderby之前的位置减少,以减少需要订购的物品。

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

根据ItemCount,这可能会给你一些&#34;提升&#34;。