HomeTutorialsArticlesAbout MeContact

JS Challenge 5: Pete the baker

By Alberto Montalesi
Published in Challenge
October 15, 2020
2 min read
Check out my Github for my free-to-read JavaScript Ebook that covers all the new features from ES6 to 2021. If you want find a great place for interactive tutorials, i recommend Educative where you can find my JavaScript course
This website contains affiliate links.

In this article we will solve together the Pete the baker challenge from CodeWars, you can find it at this link. The difficulty of this challenge is medium.

Let’s read the task together:

Pete likes to bake some cakes. He has some recipes and ingredients. Unfortunately, he is not good at maths. Can you help him to find out, how many cakes he could bake considering his recipes? Write a function cakes(), which takes the recipe (object) and the available ingredients (also an object) and returns the maximum number of cakes Pete can bake (integer). For simplicity, there are no units for the amounts (e.g. 1 lb of flour or 200 g of sugar are simply 1 or 200). Ingredients that are not present in the objects, can be considered as 0.

Examples: // must return 2 cakes({flour: 500, sugar: 200, eggs: 1}, {flour: 1200, sugar: 1200, eggs: 5, milk: 200}); // must return 0 cakes({apples: 3, flour: 300, sugar: 150, milk: 100, oil: 100}, {sugar: 500, flour: 2000, milk: 2000});

We can solve this problem in many ways but the logic behind it is simply to iterate over the keys in our Object, calculate for how many cakes an ingredient can be used, and then simply return the lowest number we got for any ingredient.

First method - For In

Let’s try to solve it using a for..in loop.

function cakes(recipe, available) {

  let maxCakes;
  for(var ingredient in recipe){

  }
}

This is the skeleton of our loop, as you can see I’ve initialized a variable maxCakes that will keep track of how many cakes we can make. Let’s continue the loop:

function cakes(recipe, available) {
  let maxCakes
  for (var ingredient in recipe) {
    if (available[ingredient]) {
      const possibleCakes = Math.floor(
        available[ingredient] / recipe[ingredient] || 0
      )
      if (!maxCakes || possibleCakes < maxCakes) {
        maxCakes = possibleCakes
      }
    } else {
      return 0
    }
  }
  return maxCakes
}

To recap:

  • we iterate over each ingredient in the recipe
  • we first check if we have that ingredient, if we don’t we return 0 as we will not be able to make any cake with a missing ingredient
  • if we have the ingredient we calculate how many cakes we can create and we round it down to the lowest integer with Math.floor
  • if maxCakes is undefined (meaning it’s the first iteration we make) or if the amount of possible cakes that this ingredient can provide us is less than the amount we calculated for another ingredient we update the value of maxCakes

There you have it, this is a simple solution using a for..in loop, let’s try one more time with a reduce method.

test

Second method - Reduce

The logic behind this solution is the same as before, just the syntax will be maybe a bit harder to read at first but more concise.

function cakes(recipe, available) {
  return Object.keys(recipe).reduce(function (val, ingredient) {
    console.log(val)
    console.log(ingredient)
    return Infinity
  }, Infinity)
}

cakes(
  { flour: 500, sugar: 200, eggs: 1 },
  { flour: 1200, sugar: 1200, eggs: 5, milk: 200 }
)

In this implementation we are calling reduce on the Array of keys of our recipe Object, passing Infinity as the first value. We do that because we don’t know what’s gonna be the max value in any of our ingredients so we need to play safe and use that instead.

If you try running the code above you will see this output:

Infinity
flour
Infinity
sugar
Infinity
eggs

We don’t want to return Infinity, what we want is to return the lowest possible number of cakes possible to make, and to do that we can change our function to look like this:

function cakes(recipe, available) {
  return Object.keys(recipe).reduce(function (val, ingredient) {
    return Math.min(
      Math.floor(available[ingredient] / recipe[ingredient] || 0),
      val
    )
  }, Infinity)
}

cakes(
  { flour: 500, sugar: 200, eggs: 1 },
  { flour: 1200, sugar: 1200, eggs: 5, milk: 200 }
)

What we changed is this line:

return Math.min(
  Math.floor(available[ingredient] / recipe[ingredient] || 0),
  val
)

What this does is get the minimum (Math.min) between the current number of cakes that we can make with this current ingredient (Math.floor(available[ingredient] / recipe[ingredient] || 0) or the value returned by the previous iteration that we are passing via the val variable.

At the first iteration, val is Infinity so any value will override it, whether it’s a positive value or just 0.

There you have it, a more concise function that does the same as the first solution we adopted.

There are many other ways of solving this problem, let me know yours in the comment.

If you liked this type of content, please let me know in the comments and I’ll create more of these.



Tags

challenge
Previous Article
JS Challenge 4: Who Likes it?

Alberto Montalesi

Software Developer

buy me coffee
complete guide to modern javascript book cover

Complete Guide to Modern JavaScript

Get the Course

Category

Article
Challenge
Tutorial

Related Posts

JS Challenge 7: Multiples of 3 or 5
October 28, 2020
1 min
© 2022, All Rights Reserved.

Quick Links

TutorialsArticlesChallenges

Social Media