查找一个项目的可能变体

时间:2014-02-07 16:36:25

标签: c# linq data-structures foreach variations

在我的申请中,我有食谱的概念,每种食谱都有可以被其他成分替代的成分。我想做的是用每种成分产生各种可能性。我有以下结构作为CLR对象:

public class Food
{
    public Food()
    {
        NutritionalValues = new Collection<FoodNutritionalValue>();
    }

    public string Name { get; set; }
    public string Category { get; set; }

    public ICollection<FoodNutritionalValue> NutritionalValues { get; set; }
}

public class FoodNutritionalValue
{
    public string Type { get; set; }
    public decimal Value { get; set; }
}

public class Recipe
{
    public Recipe()
    {
        IngredientGroups = new Collection<IngredientGroup>();
    }

    public string Name { get; set; }
    public ICollection<IngredientGroup> IngredientGroups { get; set; }
}

public class IngredientGroup
{
    public IngredientGroup()
    {
        Ingredients = new Collection<Food>();
    }

    public ICollection<Food> Ingredients { get; set; }
}

IngredientGroup是可以互相替换的东西。因此,对于配方,每个IngredientGroups都需要有一种成分。但是,由于我不知道IngredientGroups计数,我无法迭代它们以找出每种可能性。

例如,如果我事先知道IngredientGroups.Count的计数,则以下代码可以正常工作

Recipe recipe2 = new Recipe();
IngredientGroup ingredientGroup3 = new IngredientGroup();
IngredientGroup ingredientGroup4 = new IngredientGroup();
IngredientGroup ingredientGroup5 = new IngredientGroup();

recipe2.Name = "Recipe2";
ingredientGroup3.Ingredients.Add(new Food { Name = "Food8", Category = "Categor8" });
ingredientGroup3.Ingredients.Add(new Food { Name = "Food9", Category = "Categor9" });

ingredientGroup4.Ingredients.Add(new Food { Name = "Food5", Category = "Categor5" });
ingredientGroup4.Ingredients.Add(new Food { Name = "Food10", Category = "Categor10" });
ingredientGroup4.Ingredients.Add(new Food { Name = "Food11", Category = "Category11" });

ingredientGroup5.Ingredients.Add(new Food { Name = "Food3", Category = "Categor3" });
ingredientGroup5.Ingredients.Add(new Food { Name = "Food4", Category = "Categor4" });

recipe2.IngredientGroups.Add(ingredientGroup3);
recipe2.IngredientGroups.Add(ingredientGroup4);
recipe2.IngredientGroups.Add(ingredientGroup5);

var recipes = new[] { recipe2 };

List<string> results = new List<string>();
foreach (var rcp in recipes)
{
    var group1 = rcp.IngredientGroups.ElementAt(0);
    var group2 = rcp.IngredientGroups.ElementAt(1);
    var group3 = rcp.IngredientGroups.ElementAt(2);

    foreach (var item1 in group1.Ingredients)
        foreach (var item2 in group2.Ingredients)
            foreach (var item3 in group3.Ingredients)
            {
                results.Add(string.Format("{0}, {1}, {2}", item1.Name, item2.Name, item3.Name));
            }
}

我确定我错过了一些太大的东西。有谁知道如何在运行时产生各种可能性?

1 个答案:

答案 0 :(得分:1)

根据找到的答案Here,您可以使用相同的辅助方法:

public static List<List<T>> CombinationsOf<T>(List<List<T>> sets)
{    
  var combinations = new List<List<T>>();

  foreach (var value in sets[0])
    combinations.Add(new List<T> { value });

  foreach (var set in sets.Skip(1))
    combinations = AddSet(combinations, set);

  return combinations;
}

private static List<List<T>> AddSet<T>(List<List<T>> combinations, List<T> set)
{
  var result = from value in set
               from combination in combinations
               select new List<T>(combination) { value };

  return result.ToList();
}

用法示例 (基于OP的示例)

...
var foods = recipes.SelectMany(recipe => 
  recipe.IngredientGroups.Select(ingredient =>
    ingredient.Ingredients.Select(o => o.Name).ToList()));

var results = from combination in CombinationsOf(foods.ToList())
              select string.Join(", ", combination);
...

<强>输出

results :=

Food8, Food5, Food3 
Food9, Food5, Food3 
Food8, Food10, Food3 
Food9, Food10, Food3 
Food8, Food11, Food3 
Food9, Food11, Food3 
Food8, Food5, Food4 
Food9, Food5, Food4 
Food8, Food10, Food4 
Food9, Food10, Food4 
Food8, Food11, Food4 
Food9, Food11, Food4