Jofairden
Jofairden

Reputation: 95

Linq code to get the index of an object in an array from an object within a list

Actually, the title is confusing me and I'm not even sure if it's correct. I'm with the following issue here: I have a List where each recipe holds a requiredItem[] array (size 15) This required item array can hold items which are required for the recipe. What I'm tring to do is get all the recipes in a seperate list, that use wood in their recipe as one of the required items. For example, a recipe could be to need 10 wood to craft a wooden table. This recipe is within the recipe list. A quick google search made me find the following, but I can't figure out how I can access the requiredItem indexes:

 List<Recipe> rec = Main.recipe.ToList();
 rec.Select((s, i) => new { i, s })
.Where(t => t.s.requiredItem[indexhere].type == 9)
.Select(t => t.i)
.ToList()

I'm sorry I'm not seeing this, I wouldn't be surprised if the answer is really simple.

Also I tried the following. It doesn't bring up any errors, but it's actually not selecting the recipes.

        Item refItem = new Item();
        refItem.SetDefaults(ItemID.Wood, false);
        List<int> selectWood = new List<int>(rec.Select((r, i) => new { i, r }).Where(x => x.r.requiredItem.ToList().Contains(refItem)).Select(x => x.i).ToList());
        ErrorLogger.Log(selectWood.ToArray().ToString());
        List<int> indices = new List<int>();
        foreach (var indice in selectWood)
        {
            for (int i = 0; i < Main.recipe[indice].requiredItem.Length; i++)
            {
                var item = Main.recipe[indice].requiredItem[i];
                if (item.type == ItemID.Wood && item.stack >= 10) indices.Insert(0, indice);
            }
        }

        foreach (var indice in indices)
        {
            ++numberRecipesRemoved;
            rec.RemoveAt(indice);
        }

Upvotes: 1

Views: 91

Answers (2)

Bozhidar Stoyneff
Bozhidar Stoyneff

Reputation: 3634

Yes, it is simple, if I understood your question, you need to show all the recepies that contains wood as required item. So do it like this:

var woodRecipes = recipes.Where(r => r.requiredItems.Contains(wood)).ToList();

Upvotes: 1

AlanT
AlanT

Reputation: 3663

I may be misreading the question but it is not totally obvious why you need and index (indexHere) as an Any() clause should suffice.

Without details of the Recipe or requiredItem it is hard to be sure but the following seems to achieve what you need.

enum MaterialType
{
    None,
    Wood,
    Glass,
    Steel,
    Cloth
}

class Ingredient
{

    public Ingredient(MaterialType type, int amount)
    {
        Type = type;
        Amount = amount;
    }

    public MaterialType Type { get; }
    public int Amount { get; }
}

class Recipe
{

    public Recipe(string name, params Ingredient[] ingredients) 
        : this(name, (IEnumerable<Ingredient>) ingredients)
    {          
    }

    public Recipe(string name, IEnumerable<Ingredient> ingredients)
    {
        Name = name;
        Ingredients = ingredients.ToArray();
    }

    public string Name { get; }
    public Ingredient[] Ingredients { get; }
}

[TestClass]
public class FindAllItemsFixture
{

    private readonly static IEnumerable<Recipe> AllItemRecipes = new List<Recipe>
    {
        new Recipe("Sword", new Ingredient(MaterialType.Steel, 3)),
        new Recipe("Spear", new Ingredient(MaterialType.Steel, 1), new Ingredient(MaterialType.Wood, 3)),
        new Recipe("Table",  new Ingredient(MaterialType.Wood, 6)),
        new Recipe("Chair",  new Ingredient(MaterialType.Wood, 4)),
        new Recipe("Flag",  new Ingredient(MaterialType.Cloth, 2)),

    };

    IEnumerable<Recipe> GetAllRecipesUsingMaterial(MaterialType materialType)
    {
        return AllItemRecipes.Where(r => r.Ingredients.Any(i => i.Type == materialType));
    }


    [TestMethod]
    public void GetAllWoodenRecipes()
    {
        var expectedNames = new string[] { "Spear", "Table", "Chair" };
        var woodenItems = GetAllRecipesUsingMaterial(MaterialType.Wood);
        CollectionAssert.AreEqual(expectedNames, woodenItems.Select(i => i.Name).ToArray());

    }

    [TestMethod]
    public void GetAllClothRecipes()
    {
        var expectedNames = new string[] { "Flag" };
        var clothItems = GetAllRecipesUsingMaterial(MaterialType.Cloth);
        CollectionAssert.AreEqual(expectedNames, clothItems.Select(i => i.Name).ToArray());

    }
}

The important piece is the GetAllRecipesUsingMaterial() function in the unit test. It selects all the recipes that contain an ingredient of a specified type.

Upvotes: 1

Related Questions