简体   繁体   English

LINQ 查询比较两个列表与子列表

[英]LINQ Query comparing two lists with sublist

I'm making a game that has a crafting system.我正在制作一个具有制作系统的游戏。 I'm trying to get a list of recipes, but only show the ones the player has enough of in their inventory.我正在尝试获取食谱列表,但只显示玩家在他们的库存中拥有足够多的食谱。 I'm having difficulty figuring out this query.我很难弄清楚这个查询。 Here are my stripped down classes:这是我的精简课程:

public class GameItem
{
    public string itemName;
    public int quantityHeld;
}

public class GameItemRecipe : GameItem
{
    public GameItemIngredient[] giiIngredients;
}

public class GameItemIngredient : GameItem
{        
    public int quantityNeeded;
}

So I have a list of GameItems;所以我有一个 GameItems 列表; that is the player's inventory.那是玩家的物品栏。 Then I have a separate list of Recipes that the Player knows.然后我有一个玩家知道的食谱的单独列表。 The Recipes have a sub list of the ingredients required to make it.食谱有一个制作它所需成分的子列表。 So I want to get the list of recipes that have enough items in the inventory.所以我想获取库存中有足够物品的食谱列表。 Any help is appreciated.任何帮助表示赞赏。

var recipes = new List<GameItemRecipe>();
var inventory = new List<GameItem>();

var possibleRecipes = recipes.Where(rec => r.giiIngredients.
                          All(i => ing.quantityNeeded <= inventory.
                          FirstOrDefault(gi => gi.itemName== ing.itemName)?.quantityHeld));

This query takes all of your recipes, where for all of the ingredients the quantity need field is smaller or equals the quanitity held field of the game item with the same item name in your inventory lsit of game items.此查询获取您的所有食谱,其中对于所有成分,数量需求字段小于或等于游戏物品清单中具有相同物品名称的游戏物品的持有数量字段。

So you have a Player , and this Player has an Inventory , which is a sequence of GameItems .所以你有一个Player ,这个 Player 有一个Inventory ,它是一系列GameItems Some of these GameItems may be GameItemIngredients .其中一些 GameItems 可能是GameItemIngredients You didn't specify that all GameItems in the Inventory are GameItemIngredients, so it might be that some GameItems in the Inventory are not GameItemIngredients.您没有指定 Inventory 中的所有 GameItems 都是 GameItemIngredients,因此 Inventory 中的某些 GameItems 可能不是 GameItemIngredients。

Furthermore, the Player knows a sequence of GameItemRecipes .此外,玩家知道GameItemRecipes的序列。 To make one of these recipes, the player needs the GameItemIngredients that are mentioned in the recipe.要制作其中一种配方,玩家需要配方中提到的GameItemIngredients

The Player needs to know which Recipes he can make.玩家需要知道他可以制作哪些食谱。 In other words: for which Recipes does the Player have enough Ingredients.换句话说:对于哪些食谱,玩家有足够的成分。

IEnumerable<GameItem> inventory = ...
IEnumerable<GameItemRecipe> recipes = ...

From this you can extract all Ingredients that the Player has in his Inventory:从中您可以提取玩家在他的库存中拥有的所有成分:

IEnumerable<GameItemIngredient> ingredients = inventory.OfType<GameItemRecipe>();

Requirement: Give me all Recipes that the Player can make;要求:给我玩家可以制作的所有食谱; which are all Recipes that the Player has all Ingredients for.这些都是玩家拥有所有成分的食谱。

Every GameItemIngredient has a property RequiredQuantity .每个 GameItemIngredient 都有一个属性RequiredQuantity I assume that every Recipe will have unique names for the GameItemIngredients that are needed to make the Recipe.我假设每个食谱都会有制作食谱所需的 GameItemIngredients 的唯一名称。

Simply said: if you need two Potatoes to make Recipe "Mashed Potatoes", then the Ingredients list of the Recipe will contain only one Ingredient with the Name "Potato".简单地说:如果你需要两个土豆来制作食谱“土豆泥”,那么食谱的成分列表将只包含一种名称为“土豆”的成分。 This Ingredient will have quantity 2. So you will not have the Ingredient Potato twice in your Recipe.该成分的数量为 2。因此,您的食谱中不会出现两次土豆成分。

Furthermore I assume, that you don't do sub-classing in your Recipes: if your Recipe requires an "Apple", and you have a "Granny Smith" in your Inventory, then alas, you can't make the Recipe, even though a "Granny Smith" is an "Apple".此外,我假设您不会在食谱中进行子分类:如果您的食谱需要“苹果”,并且您的库存中有“史密斯奶奶”,那么唉,您无法制作食谱,甚至虽然“Granny Smith”是“Apple”。

A Recipe can be made, if all Ingredients of the Recipe are in the Ingredients of the Inventory AND the QuantityNeeded <= QuantityHeld .如果配方的所有成分都在库存的成分中并且QuantityNeeded <= QuantityHeld ,则可以制作配方。

So for every Recipe we will need to check whether the Ingredients are in the Inventory.因此,对于每个配方,我们都需要检查成分是否在库存中。 To make this efficient, we will make a Dictionary of the Ingredients that are in the Inventory.为了提高效率,我们将制作库存中成分的字典。 Key is the ItemName of the Ingredient; Key是成分的ItemName Value is the QuantityHeld值是QuantityHeld

var ingredientQuantities = ingredients.ToDictionary(
    ingredient => ingredient.ItemName,
    ingredient => ingredient.QuantityHeld);

Consider to use an EqualityComparer if "Apple" is the same ingredient as "apple"如果“Apple”与“apple”的成分相同,请考虑使用 EqualityComparer

The ItemName of every ingredient of a Recipe should be a key in the Dictionary, AND the QuantityNeeded <= QuantityHeld (= value in the Dictionary)配方中每种成分的 ItemName 应该是 Dictionary 中的一个键,并且 QuantityNeeded <= QuantityHeld (= Dictionary 中的值)

var recipesThatCanBeMade = recipes
   .Where(recipe => !recipe.Ingredients.All(ingredient =>
       ingredientQuantities.TryGetValue(ingredient.ItemName, out int quantityHeld)
       && ingredient.QuantityNeeded <= quantityHeld)

In words: from every recipe in the sequence of recipes, keep only those recipes where换句话说:从食谱序列中的每个食谱中,只保留那些食谱

  • ALL ingredients have an ItemName that is a key in the dictionary,所有成分都有一个 ItemName ,它是字典中的一个键,
  • AND have a QuantityNeeded that is smaller or equal to the QuantityHeld that is the corresponding value in the Dictionary.并且有一个 QuantityNeeded,它小于或等于 Dictionary 中对应值的 QuantityHeld。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM