Working my way through an Object

I have an constant that looks like this:

const recipeObj = {
      "Recipe1": [
        "water",
        //a bunch more ingredients
      ],
      "Recipe2": [
        "EVOO",
        //a bunch more ingredients
      ]
    }

I am creating a function that:

  1. Is sent a value based on user interaction.
  2. That value is checked against the ingredients in recipeObj.
  3. If it matches, then I want to store the recipe name to print somewhere else.

I looked through the Object methods to see what I could use to no avail. Anyone have any ideas?

Thanks!

You could iterate through object values using for … of loop and each value is an array so you can use array method like includes() to see if the item is there.

Edit: my bad, forgot that (for ... of) doesn’t work for objects. You can use (for ... in) instead to iterate over keys.

1 Like

Hi,

You could use Object.entries.

For checking to see if the Object value has the item you could put the array into a new Set() then fire off a Set.has(ITEM) to return a boolean.

1 Like

One option, which means more logic up front (but makes actually working with the data much easier) would be to have the inverse defined as well, and every time the recipe object is updated, update this as well:

const ingredientsObj = {
  water: [Recipe1, Recipe5],
  foo: [Recipe2, Recipes],
  ...
}

Otherwise, you need to traverse possibly the entire recipe object tree every time you want something. As an example, one approach if you stick to doing that:

function getRecipes (recipeObj, ingredient) {
  const recipes = []
  for (const [recipe, ingredients] of Object.entries(recipeObj)) {
    if (ingredients.includes(ingredient)) recipes.push(recipe)
  }
  return recipes;
}
1 Like

So, I got a little ahead of myself.

Before I could tackle the problem I posted about, I had to take a step back and get my data to look like this in the first place:

    {
      "Recipe1": [
        "water",
        //a bunch more ingredients
      ],
      "Recipe2": [
        "EVOO",
        //a bunch more ingredients
      ]
    }

I have almost got it but I think I am getting stuck in map() and for...loops and over-writing my results so instead of ending up with data as in the format above, I am ending up with only the FINAL object value. So in the case above, the final result is:

{
"Recipe2": [
        "EVOO",
        //a bunch more ingredients
      ]
    }

This is obviously incomplete but I am not sure where in my loops I am over-writing. Can someone take a look?

Code is here: https://codesandbox.io/s/wash-po-recipes-bqx4j?fontsize=14
Component: readData.jsx
Event: buildRecipeObject()

Goal of this event:

//Starting point - each element of array looks like this:
    //{title: "Polenta With Balsamic Scallion Greens",
    // Link: "Polenta With Balsamic Scallion Greens",
    // ingredient1: "water",
    // ingredient2: "kosher salt",
    // ...}

    // Final result has to look like this:
    // {
    //   "RecipeNumber1": ["ingredient1", ...],
    //   "RecipeNumber2": ["ingredient1", ...],
    //   ....
    // }

Thank you.

Is it literally “ingredient1/2/3/4” every time (and can you guarantee its always named that way)?

Yes, the column headings in original XLS file are ingredient1/2/3 etc.

I did manage to implement this - so yay!!

function getRecipes (recipeObj, ingredient) {
  const recipes = []
  for (const [recipe, ingredients] of Object.entries(recipeObj)) {
    if (ingredients.includes(ingredient)) recipes.push(recipe)
  }
  return recipes;
}

Of course it runs only on one recipe so far.

2 Likes

So I tried to work on this problem some more.

Here is my new code: https://codesandbox.io/s/wash-po-recipes-zu92s?fontsize=14

I really thought I had come up with the right code but I am STILL only getting the last recipe (as noted in my earlier post here).

Can anyone take a look at my code, specifically:
Component: readData.jsx
Event: buildRecipeObject()

Expected:

 // Final result has to look like this:
    // {
    //   "RecipeNumber1": ["ingredient1", ...],
    //   "RecipeNumber2": ["ingredient1", ...],
    //   ....
    // }

Actual:

{
"Recipe2": [
        "EVOO",
        //a bunch more ingredients
      ]
    }

Thank you.

Look at what you are passing to buildeRecipeObject.

Add console.log(allRecipes) inside the method.

It’s returning an array of objects, as expected:

Code:

buildRecipeObject(allRecipes) {
    console.log("allRecipes");
    console.log(allRecipes);
    let eachRecipe = {};
    allRecipes.map(each => {
//more code....
});
    this.setState({
      eachRecipe: eachRecipe
    });

That is odd. When I open your codesanboxbox.io link from above and click the Run button after adding the console.log, I do not get that at all. Do you have another version or something?

Sorry I was just making the changes in VS Code. Here is the same updated code in sandbox: https://codesandbox.io/s/wash-po-recipes-dxgej?fontsize=14

I do see that console.log (in CodeSandbox) does not produce the same results I saw in my local browser…but does that have to do with how CodeSandbox works…?

Edit: I also added some more console.logs to see what the value of each was in the map() method. So you will see a lot more things logged than just what you were asking about.

So it turns out that I was not using the spread operator 100% correctly.

Instead of:
eachRecipe = { ...eachRecipeKeyValuePair };

It should be:
eachRecipe = { ...eachRecipe, ...eachRecipeKeyValuePair };

Problem solved!!! So. Happy.