JS Challenge 5: Pete the baker

JS Challenge 5: Pete the baker
Check out my Github for my free-to-read JavaScript Ebook that covers all the new features from ES6 to 2019. If you want find a great place for interactive tutorials, i recommend Educative where I'm currently finishing to build my JavaScript course.
This website contains affiliate links. See my disclosure about affiliate links here

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.

JS Challenge 6: Convert string to camel case

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.


Thank you very much for reading, if you enjoyed this article, please share it with friends and colleagues and if there is a topic you would like me to cover, reach out to me on twitter at @montalesi. Follow me on DevTo or on Twitter for more.

complete guide to modern javascript alberto montalesi ebook bannerGet my ebook on Amazon and Leanpub or get my course on Educative


NEWEST ARTICLES




ABOUT ME

author alberto montalesi profile picture

Alberto is a software developer specialized in building enterpise software using Angular and author of the 'Complete guide to Modern JavaScript' ebook and course. In his free time he writes articles and tutorials on InspiredWebDev.com and Dev.to

You can read more about him here