"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > An (Im)mutable Shopping List for a Delicious Pesto Pasta

An (Im)mutable Shopping List for a Delicious Pesto Pasta

Published on 2024-08-22
Browse:785

An (Im)mutable Shopping List for a Delicious Pesto Pasta

Pesto pasta is proof that G-d exists

There are few things in life that give me more pleasure than a heaping helping of fresh pesto over homemade Capellini (Angel Hair). I'm a bonafide foodie - especially when it comes to Italian cuisine - and am always trying more complex recipes, but the simplicity and enjoyment of such a minimalist dish never ceases to satisfy. If I had the (mis)fortune of choosing a last meal it would be a tough decision between sushi and pesto over pasta, but I still think pesto pasta wins out in the end.

All this talk of pesto is making me hungry

What am I to do? Well, make pesto pasta of course. Sometimes you just gotta say, "Quando a Roma!"

Lets start by making a list of ingredients to buy from our friendly Italian Market, "Il Mercato di Giovanni." We will create our shopping list from two recipes using both immutable and mutable object arrays. While it would be more efficient to simply write out what we need, you know that this is just way more fun. I can tell you're starving for more on how we can program our way to pesto pasta, so let's dig right in. "Mangia Mangia!"

Creating separate pasta and pesto recipe arrays

We'll start by declaring variables for pastaRecipeArray and pestoRecipeArray, with each variable assigned to an array of objects, where each object represents an individual ingredient.

When we assign array values to each variable we use the Object.freeze() method to ensure that they are immutable. (more on this later)

Each recipe object has three properties, with key-value pairs as follows:

  • 'name' = The name of the ingredient in the form of a 'string'
  • 'recipe' = A value or values, in the form of an 'array', indicating which recipe(s) the ingredient is needed for (pasta, pesto, or both)
  • 'price' = The price of the ingredient in USD, in the form of a 'number', using fairly unrealistic dummy content

(note: I've ommitted quantities and other details to keep things brief and relatively simple in this post. We could also implement these objects using JSON, but we are keeping things easy to digest here.)

The code to establish these arrays will look something like this:

const pastaRecipeArray = Object.freeze([
  { "name": "Eggs", "recipe": ["pasta"], "price": 6.99 },
  { "name": "Extra Virgin Olive Oil", "recipe": ["pasta", "pesto"], "price": 12.59 },
  { "name": "Kosher Salt", "recipe": ["pasta", "pesto"], "price": 7.89 },
  { "name": "Semolina Flour", "recipe": ["pasta"], "price": 12.95 }
])

const pestoRecipeArray = Object.freeze([
  { "name": "Basil", "recipe": ["pesto"], "price": 6.99 },
  { "name": "Black Pepper", "recipe": ["pesto"], "price": 9.99 },
  { "name": "Extra Virgin Olive Oil", "recipe": ["pasta", "pesto"], "price": 12.59 },
  { "name": "Kosher Salt", "recipe": ["pasta", "pesto"], "price": 7.89 },
  { "name": "Parmesan", "recipe": ["pesto"], "price": 15.99 },
  { "name": "Pine Nuts", "recipe": ["pesto"], "price": 13.98 }
])

You'll notice again that the recipe key points to a value that is in the form of an array. We set it up this way because some ingredients are used in both recipes.

To test that pastaRecipeArray is set up properly we can utilize the .forEach() method, a callback function used to iterate over each object in the array. Using ingredient as the parameter, we can log it into the console as follows:

pastaRecipeArray.forEach((ingredient) => {
  console.log(ingredient)
})

When you inspect the console you should see something like the following output:

Object {name: "Eggs", recipe: Array(1), price: 6.99}
Object {name: "Extra Virgin Olive Oil", recipe: Array(2), price: 12.59}
Object {name: "Kosher Salt", recipe: Array(2), price: 7.89}
Object {name: "Semolina Flour", recipe: Array(1), price: 12.95}

Similarly, we can log our pestoRecipeArray like this:

pestoRecipeArray.forEach((ingredient) => {
  console.log(ingredient)
})

Which results in the following:

Object {name: "Basil", recipe: Array(1), price: 6.99}
Object {name: "Black Pepper", recipe: Array(1), price: 9.99}
Object {name: "Extra Virgin Olive Oil", recipe: Array(2), price: 12.59}
Object {name: "Kosher Salt", recipe: Array(2), price: 7.89}
Object {name: "Parmesan", recipe: Array(1), price: 15.99}
Object {name: "Pine Nuts", recipe: Array(1), price: 13.98}

(note: When you see output such as Array(1) and Array(2) you would either want to rewrite the function to select those keys or simply click on the array in the console to see the details of what it contains.)

Creating a Shopping List Array

Now that we've established our recipe arrays we want to move on to the next step, creating a shopping list array. To do this we will want to combine our object arrays pastaRecipeArray and pestoRecipeArray into a new mutable variable named shoppingListArray. We will do this using the spread operator ... like so:

const shoppingListArray = [...pastaRecipeArray, ...pestoRecipeArray]

Now let's use the following console.log() to see what our new list looks like. Moving forward we will log property values within the object rather than the full object, to remove some of the clutter. You will want to use this code to see how our list changes after each step of the process.

shoppingListArray.forEach((ingredient) => {
      console.log(ingredient.name)
})

We can see that our lists have been joined together into one in the console, this time only logging each ingredient name.

Eggs
Extra Virgin Olive Oil
Kosher Salt
Semolina Flour
Basil
Black Pepper
Extra Virgin Olive Oil
Kosher Salt
Parmesan
Pine Nuts

Immutable vs. mutable arrays

Why should we make pastaRecipeArray and pestoRecipeArray immutable? Making them immutable makes it so that we can't change their values after they are assigned. We don't want to just tear these recipes up. We want to save them for another glorious day. Those immutable family recipes need to live on, regardless of what we are about to write on our temporary, mutable shopping list.

We also want to be able to add or substract ingredients from our newly created shoppingListArray to make this dish to our specific tastes, without affecting our original recipes of course.

Adding, replacing, and deleting ingredients

As you may have noticed, when we combined our pasta and pesto recipes into our shopping list we ended up with duplicates for "Extra Virgin Olive Oil" and "Kosher Salt". We don't need to buy these twice so let's get rid of them. There are fancier ways to eliminate duplicates, but for now we will use .splice() to remove the first Extra Virgin Olive Oil object.

The .splice() method destructively deletes or replaces elements in an array. The first parameter represents the first element we are deleting and the second parameter represents how many elements we want to delete from that start point. While "Extra Virgin Olive Oil" is the second object in the array, arrays start at '0', so technically the second object is represented by a '1'. Let's execute the following:

shoppingListArray.splice(1, 1)

In the console you will see that there is now only one "Extra Virgin Olive Oil" object. (note: If you try to use .splice() or similar methods on one of our original recipe arrays you will get a TypeError because we used Object.freeze(), making them immutable.)

We still have an extra "Kosher Salt", and now we are going to use .splice() to it's full power. In addition to our first two parameters we have a third parameter that can replace elements in an array with new elements. I love to add a bit of lemon to my pesto, and I don't like food that is too salty, so let's go ahead and replace our extra "Kosher Salt" with our new "Lemon" object. We will declare our lemon object as a variable for better readibility and include it as the third .splice() parameter.

const lemon = { "name": "Lemon", "recipe": ["pesto"], "price": 2.04 }

shoppingListArray.splice(6, 1, lemon)

Today I'm feeling a bit saucy so let's change things up a bit and add in some roasted tomatoes using .push(). With .push() we can add elements to the end of the array, with each parameter representing a new element. So let's add some "Cherry Tomatoes" to our list. Come to think of it, I forgot the "Garlic" too!

const tomatoes = { "name": "Cherry Tomatoes", "recipe": ["pesto"], "price": 5.99 }

const garlic = { "name": "Garlic", "recipe": ["pesto"], "price": 2.99 }

shoppingListArray.push(tomatoes, garlic)

Organizing our shopping list

Now that we have all our ingredients well established let's organize them in a way that will make our shopping experience seamless.

Let's organize our list alphabetically using .sort().

shoppingListArray.sort((a, b) => {
  const nameA = a.name
  const nameB = b.name

  if (nameA  nameB) {
    1
  }
  return 0
})

Our shopping list now looks like this in the console.

Basil
Black Pepper
Cherry Tomatoes
Eggs
Extra Virgin Olive Oil
Garlic
Kosher Salt
Lemon
Parmesan
Pine Nuts
Semolina Flour

Planning ahead for our expected costs

Now we are ready to go to the market, but first let's make sure we know how much money we need, using .reduce(). There is a lot to go over with .reduce(), and I'm getting hungry, so I'll skip over the details.

const ingredientsPrice = shoppingListArray.reduce((accumulator, ingredient) => {
  return accumulator   ingredient.price
}, 0)

console.log("You will need $"   ingredientsPrice   " to make pesto pasta. Man is life is expensive.")
// You will need $98.39 to make pesto pasta. Wow, life is expensive.

Creating new recipe list arrays

So we went to the store and got our ingredients, but now we want to separate our ingredients back into their respective recipes, just to lay everything out on the table and keep things in order. Lets create two new arrays, pastaIngredients and pestoIngredients using .filter(), .includes(), and of course .forEach() to log them to the console.

const pastaIngredients = shoppingListArray.filter((ingredient) => {
  return ingredient.recipe.includes('pasta')
})

pastaIngredients.forEach((ingredient) => {
  console.log(ingredient.name)
})
const pestoIngredients = shoppingListArray.filter((ingredient) => {
  return ingredient.recipe.includes('pesto')
})

pestoIngredients.forEach((ingredient) => {
  console.log(ingredient.name)
})

"Wrapping" it up

As you can see from logging these to the console we successfully created a shoppingListArray that didn't modify our original immutable recipe arrays, pastaRecipeArray and pestoRecipeArray. We then were able to mutably modify the shoppingListArray in a destructive manner to add, delete, and replace ingredients to our liking. We also calculated how much we needed to spend before going to the store. Lastly, we were able to separate these ingredients back into their respective recipes, pastaIngredients and pestoIngredients in preparation for a brilliant meal.

Well, what a delicious dish that was. I hope you enjoyed it as much as I did. Again, Mangia Mangia!

Release Statement This article is reproduced at: https://dev.to/lakadaize/an-immutable-shopping-list-for-a-delicious-pesto-pasta-2jd6?1 If there is any infringement, please contact [email protected] to delete it
Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3