Как вы конвертируете несколько вложенных циклов в лямбду или linq, если у вас сложная структура объекта?

1

У меня возникают проблемы при попытке конвертировать мои несколько вложенных циклов в выражение лямбда или 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;
                    }
                }
            }
        }
    }

Я полагаю, что следует отметить, что цикл работает полностью, как ожидалось. Я просто думаю, что он лямбда /linq более чист для чтения.

EDIT: Вот другие объекты:

    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; }
}
Теги:
linq
loops
lambda

2 ответа

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);
  • 0
    Это удивительное объяснение! Мой первый вопрос о последней части (где selected.Ingredients.Any (x => selectedIngredients.Contains (x))). В последней части я получаю эту ошибку: не могу преобразовать из 'System.Collections.Generic.IEnumerable <RecipeTrackerMVC.Models.Search.Ingredient>' в 'System.Linq.ParallelQuery <RecipeTrackerMVC.Models.Ingredient>'. Мне нужно сравнить свойство id моделей. Ингредиент для поиска. Ингредиент? (Объекты разные). Кроме того, по запросу. ForEach я получаю сообщение об ошибке, в котором говорится, что он не содержит определения для ForEach.
  • 0
    @Yecats О да, я пропустил, чтобы их сравнивали по их идентификаторам. Я спроецировал каждый ингредиент в каждой последовательности на их идентификаторы. Я также изменил код, чтобы использовать Intersect вместо двух операторов Any . Кроме того, ForEach определен только в List<T> не в IEnumerable<T> поэтому я изменил его на обычный foreach .
Показать ещё 10 комментариев
0

Обратите внимание на следующую часть,

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

2 вещи пахнут здесь: во-первых, вы должны поменять or-condition, чтобы сначала проверить String.IsNullOrEmpty, а затем поставить там, где перед порядком, чтобы уменьшить элементы, которые нужно заказать.

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

В зависимости от ItemCount это может дать вам довольно "импульс".

Ещё вопросы

Сообщество Overcoder
Наверх
Меню