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){
}
}
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
isundefined
(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 ofmaxCakes
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}
)
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.
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
Top comments (1)