DEV Community

Cover image for JavaScript Challenge 5: Pete the baker
AlbertoM
AlbertoM

Posted on • Originally published at inspiredwebdev.com

JavaScript Challenge 5: Pete the baker

This article was originally posted on my blog. Head over to inspiredwebdev.com for more articles and tutorials. Check out my JavaScript course on Educative to learn everything from ES6 to ES2020.

 

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){

  }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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.

 

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}
)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}
)
Enter fullscreen mode Exit fullscreen mode

What we changed is this line:

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

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.


If you want to learn everything about JavaScript from ES6 all the way to ES2020, please check out my book available to read for free on Github. A course is also on Educative

Alt Text

 

Top comments (1)

Collapse
 
zerodragon profile image
Zero Dragon
const cakes = (recipe, available) => 
  Math.min(...Object.keys(recipe).map(ingredient =>
    Math.floor(available[ingredient] / recipe[ingredient]) || 0
  ))
console.log(cakes(
  {"flour": 500, "sugar": 200, "eggs": 1},
  {"flour": 1200, "sugar": 1200, "eggs": 5, "milk": 200}
)) // 2
Enter fullscreen mode Exit fullscreen mode