1️⃣ Pete likes to bake some cakes. He has some recipes and ingredients. Unfortunately he is not good in maths. Can you help him to find out, how many cakes he could bake considering his recipes?
2️⃣ 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.
3️⃣ 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});
🚩문제해석
레시피(recipe)에 따라 주어진 재료(ingredient)로 만들 수 있는 케이크의 최대 개수를 구하시오. 레시피와 재료는 모두 Object type으로 주어진다. 또한 재료에 대한 단위는 생각하지 말고 숫자로 접근하고 만약에 재료의 이름이 없다면 그 재료는 주어지지 않은 것이라고 본다.( 0으로 간주함)
1 function cakes(recipe, available) {
2 let min;
3 const recipeKey = Object.keys(recipe);
4 const availableKey = Object.keys(available);
5 recipeKey.forEach(ele => {
6 if(availableKey.includes(ele)){
7 let tmp = Math.floor(available[ele] / recipe[ele]);
8 min = min === undefined ? tmp : (tmp < min ? tmp : min);
9 }
10 else min = 0;
11 });
12 return min;
13 }
첫번째 생각
레시피에 있는 재료가 주어진 재료에 있는지를 먼저 확인해야했다. 만약에 주어진 재료에 레시피 재료가 1개라도 없다면, 케이크를 한 개도 만들 수 없다. 이 때 사용한 것은 Object.keys() 메소드이다.
Object.keys()
객체의 키값(속성 이름)을 배열로서 반환한다.
```
Object.key() 메소드는 이 문제를 배열로서 접근할 수 있게 만들어 준다. 그래서 forEach()**(라인 5)**와 includes()**(라인 6)**를 통해서 레시피와 재료를 매칭시켰다.
두번째 생각
이제 만들 수 있는 케이크의 개수를 구해야 한다. 같은 키값을 지닌 레시피와 재료를 /
을 통해서 나온 몫이 만들 수 있는 개수가 된다. 하지만 재료마다 만들수 있는 개수가 다르기 때문에 그 중에서 가장 작은 값이 주어진 재료로 만들수 있는 최대값이 된다. (라인 7,8)
세번째 생각
forEach()로 순회를 하면서 나온 개수의 값을 어떻게 비교할 것인가? 변수 min
과 변수tmp
을 순회 할 때마다 비교하여 작은 값을 min
담아주었다. 하지만 이 때, 첫번째 순회인 경우엔 비교할 값이 없기 때문에 비교하지 않고 tmp
값을 min
에 넣어주어야 한다. 이러한 첫번째 순회에서의 예외(?)를 해결하기 위해서 자바스크립트에서는 변수를 선언만하고 할당하지않으면 초기값으로 undefined
값을 갖게 된다는 것을 이용하였다. (라인 8)
🔽 나와 비슷한 접근이지만 reduce()와 논리연산자를 활용한 더 깔끔한(?) 풀이이다.
1 function cakes(recipe, available) {
2 return Object.keys(recipe).reduce(function(val, ingredient) {
3 return Math.min(Math.floor(available[ingredient] / recipe[ingredient] || 0), val)
4 }, Infinity)
5 }
val
값에 최소값이 지속적으로 할당되어서 최종적으로 Math.min(n, Infinity)
의 결과값은 항상 n
이다. 왜냐하면 어떠한 수 <= Infinity
이기 때문이다. 이러한 이유로 최소값을 구할 때의 초기값으로 적합하다고 볼 수 있다. 나의 코드와 비교해보면 나는 첫번째 순회에서의 비교값을 담기 위해서 undefined
를 이용했다. 같은 의도를 다르게 표현했다고 보면 될 것 같다.🔽 for문을 통한 좀 더 직관적인(?) 풀이
1 function cakes(recipe, available) {
2 var numCakes = [];
3 for(var key in recipe){
4 if(recipe.hasOwnProperty(key)){
5 if(key in available){
6 numCakes.push(Math.floor(available[key] / recipe[key]));
7 }
8 else{
9 return 0;
10 }
11 }
12 }//for in
13 return Math.min.apply(null, numCakes);
14 }
for (variable in object) { ... }
object : 접근할 객체
varialble : 접근할 객체의 속성을 변수로 지정한 것
object.hasOwnProperty(key)
object가 특정 속성을 가지고 있는지를 나타내는 boolean값을 리턴 한다.
in 연산자
명시된 속성(property)이 명시된 객체(object)에 존재하면 true를 반환하고 그렇지 않으면 false를 반환한다.
property in object
object : 객체의 이름
property : 속성이름을 나타내는 문자열(그에 대응하는 변수)
✅ hasOwnProperty()와 in연산자의 비교
if(available.hasOwnProperty(key))
라고 적어도 무방하다.func.apply(thisArg, argsArray)
func : 사용할 메소드
thisArg : func 를 호출하는데 사용될 this 의 값을 나타낸다.(사용될 객체의 값을 나타낸다.) null 일 경우, 전역 객체로 대체된다.
arrsArray : func에 전달될 인수로서 유사배열로서 전달된다. 전달되는 인수가 없는 경우, null 또는 undefined 이다.
> apply() 를 사용하는 이유 : 유용한 메소드들을 재사용이 가능해지고 반복을 피할 수 있다.
## 결론
이 문제는 수학적 해석을 어떻게 코드로 구현 할 것인가를 물어보는 문제라 생각한다. 그걸 해결하는 과정에서 object의 속성에 어떻게 접근할 것인가에 대해서 알게 되었다. 또한 reduce()가 사용되는 상황에 대해서 알게 되었다. 다른 사람들의 풀이들을 보면서 접근 방법은 비슷하지만 좀 더 효율적인 코드 혹은 또다른 방법을 배우게 되었다.
## 참고
[MDN Object.keys()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/keys)
[MDN Infinity](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Infinity)
[MDN for in](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...in)
[in 연산자](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/in)
[The Difference Between in and hasOwnProperty in JavaScript](https://masteringjs.io/tutorials/fundamentals/hasownproperty)
[Function.prototype.apply()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)
> 🚀 문제를 풀어나갈 때 생각의 흐름을 정리합니다. 또한 새로운 풀이에 대한 코드를 분석하고 모르는 부분에 대해서 정리합니다. 생각이 다른 부분에 대한 피드백은 언제나 환영합니다. 틀린 내용에 대한 피드백 또한 항상 감사합니다.