이제 3주차 막바지이다. 🤔
앞의 koans
와 testbuilder
가 쉬운 것은 아니지만....
Underbar
와는 차이가 꽤 나므로, 여긴 집중해서 풀어봐야겠다:)
주석의 내용은 아래를 풀다보면 알게되지 않을까 싶다.
말그대로 받은 값을 그대로 리턴한다.
// 만약 함수에 iterator가 필요하고,뭐라도 넘겨줘야 하는 상황에는 이 함수가 유용할 것이다.
_.identity = (val) => {
return val;
};
적응을 위해 초기 답안이 주어져있다.
일관성을 위해 Arrow function으로 바꾸었다.
// 배열의 처음 n개의 element를 담은 배열을 리턴하세요.
// 만일 n이 undefined일 경우, 단순히 첫번째 element를 리턴하세요.
_.first = (array, n) => {
return n === undefined ? array[0] : array.slice(0, n);
};
_.first와 비슷하게 작성하였다.
뒤 코드가 좀 억지스럽지만 후에 문제가 있을 경우 변경해야겠다.
// first와 비슷하게, 마지막 n개의 element를 담은 배열을 리턴하세요.
// 만일 n이 undefined일 경우, 단순히 마지막 element를 리턴하세요.
_.last = (array, n) => {
return n === undefined ? array.unshift() : array.reverse().slice(0, n).reverse();
};
velog에 적어야겠다고 결심한 순간은 _.each
부터이다.
배열과 배열이 아닐 때를 분리하여 반복문을 작성하면 된다.
// iterator(value, key, collection)를 collection의 각각의 key-value pair에 대해 호출하세요.
// iterator는 함수로 전달되며, 쉽게 말해 반복해서 실행하는 함수입니다.
// collection으로 배열과 객체를 다 받을 수 있어야 합니다.
_.each = (collection, iterator) => {
if(Array.isArray(collection)) {
for(let i = 0; i < collection.length; i += 1) {
iterator(collection[i], i, collection);
}
} else {
for(let i in collection) {
iterator(collection[i], i, collection);
}
}
};
앞의 _.each
를 활용해야한다.
만약 일치하는 index를 발견하면 더 이상 진행하면 안되므로 resultIndex === -1
조건을 추가하였다.
break
는 금지되어있다...
// target으로 전달되는 값이 array에서 발견되면, 그 index를 리턴하세요.
// 만일 array에서 발견할 수 없다면 -1을 리턴하세요.
_.indexOf = (array, target) => {
let resultIndex = -1;
_.each(array, (item, index) => {
if (item === target && resultIndex === -1) {
resultIndex = index;
}
});
return resultIndex;
/* TEST with map
const res = array.map((val, i) => val === target ? i : undefined);
return res === undefined ? -1 : res;
*/
};
두번째 인자가 test
라고 되어있어서 헷갈려서 f
로 변경하였다.
collection을 돌면서 true일 경우 result에 추가한다.
// 테스트 함수를 통과하는 모든 element를 담은 배열을 리턴하세요.
_.filter = (collection, f) => {
let result = []
_.each(collection, (num) => {
f(num) && result.push(num);
})
return result;
};
_.filter
와 정반대이다.
_.each
를 사용해도 별 차이없다. 잘못푼것일수도...
문제가 생기면 수정해야겠다!
// 테스트 함수를 통과하지 않는 모든 element를 담은 배열을 리턴하세요.
_.reject = function(collection, f) {
// TIP: _filter()를 사용하여, 변경하세요..!
let res = []
_.filter(collection, (num) => {
!f(num) && res.push(num);
})
return res;
};
값이 없으면 빈 배열에 push하여 값을 구한다.
_.each
는 foreach
느낌으로 사용하면 된다.
// element가 중복되지 않는 새로운 array를 만드세요.
// ex: [1,2,4,4,3,3] -> [1,2,4,3]
_.uniq = (array) => {
let res = [];
_.each(array, (item) => {
!res.includes(item) && res.push(item);
});
return res;
};
iterator
를 함수라 생각하고 풀면 간단하다.
배열을 돌면서 함수의 결과값을 넣어준다.
// iterator를 각 element에 적용한 결과를 담은 새로운 array를 리턴하세요.
_.map = (collection, iterator) => {
let res = [];
_.each(collection, (item) => {
res.push(iterator(item))
})
return res;
};
_.map
적응을 위하여 주어지는 코드이다.
객체로 구성된 배열에서 키로 접근하여 값을 배열로 리턴한다.
// 객체의 배열을 가져와서, 그 안에 있는 특정 속성의 값의 배열을 리턴하세요.
/* TEST EX
var people = [
{ name: 'moe', age: 30 },
{ name: 'curly', age: 50 }
];
expect(_.pluck(people, 'name')).to.eql(['moe', 'curly']);
*/
_.pluck = (collection, key) => {
return _.map(collection, (item) => {
return item[key];
});
};
Part.1 마지막 문제다운 문제다.
collection
의 iterator
를 iter
로 가져오고,
조건에 맞게 accumulator
가 undefined
이면 배열의 첫 요소를 전달하고, iter
를 진행한다.
undefined
가 아니라면 그대로 accmulator
에 iterator
를 집어넣고,
undefined
라면 한번 진행한 iter
에서 돌게되어 두번째 요소부터 반복한다.
// 각 항목에 대해 iterator(accumulator, item)를 반복적으로 호출하여,
// Reduces an array to a single value by repetitively calling
// 하나의 값으로 줄입니다. accumulator는 누적값으로, 이전 iterator 호출의 반환값이어야 합니다.
//
// reduce에 대한 세번째 argument로 초기값을 전달 할 수 있습니다.
// 만일 초기값이 전달되지 않으면, 첫번재 element가 accumulator로 사용되며, iterator에 전달되지 않습니다.
// 즉, 초기값이 전달되지 않은 경우, iterator는 두번째 element로부터 시작합니다.
_.reduce = (collection, iterator, accumulator) => {
const iter = collection[Symbol.iterator]();
if(accumulator === undefined){
accumulator = collection[0];
iter.next();
}
for(const i of iter) {
accumulator = iterator(accumulator, i);
}
return accumulator;
};