Lodash의 _.flatten() 써보기.
우선 _.flatten을 만들면서 재사용한 _.each()부터.
_.each = function (collection, iterator) {
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iterator(collection[i], i, collection);
}
} else if (collection && typeof collection === 'object') {
for (const key in collection) {
iterator(collection[key], key, collection);
}
}
}
_.some()도 사용했다.
_.some = function(collection, iterator) {
iterator = iterator || _.identity;
return !_.every(collection, item => !iterator(item));
}
_.some은 _.every()를 사용했네.
_.every = function(collection, iterator) {
iterator = iterator || _.identity;
return _.reduce(
collection,
(accumulator, item) => iterator(item) ? accumulator : false,
true
)
이건 또 _.reduce()를 사용했다. 귀찮지만 복습한다 생각하고 계속 거슬러 올라가자.
_.reduce = function(collection, iterator, accumulator) {
if (accumulator !== undefined) {
_.each(collection, function(item) {
accumulator = iterator(accumulator, item)
})
} else if (accumulator === undefined) {
accumulator = collection[0];
for (let i = 1; i < collection.length; i++) {
accumulator = iterator(accumulator, collection[i]);
}
}
return accumulator;
}
그럼 본격적으로 _flatten(). 배열 속에 배열이 있으면 요소들을 꺼내서 가장 바깥쪽 배열로 옮겨주는 함수. 즉 배열의 깊이?를 없애는 함수. 배열 속 배열 속에 배열 속 배열 속 배열 속 배열 속 배열이 계속 있을 수 있다.
_.reduce()를 재사용해서 짜보려다가 실패만 무수하게 겪었다. 그러다가 새로 배운 재귀함수를 써보기로. 처음이라 좀 힘겨웠다.
고난 끝에 처음으로 성공한 코드는
_.flatten = function(nestedArray, result) {
result = [];
if (!_.some(nestedArray, Array.isArray)) {
result = result.concat(nestedArray);
} else {
for (let i = 0; i < nestedArray.length; i++) {
let element = nestedArray[i];
if (!Array.isArray(element)) result.push(element);
else result = result.concat(_.flatten(element));
}
}
return result;
};
주어진 함수 속에 배열이 또 있는지 먼저 확인한다. 없으면 result에 해당 배열을 덧붙이고 result로 다시 할당한다.
배열이 안에 또 있으면 배열을 쭉 훑으면서 배열이 아닌 요소는 result에 밀어넣고 배열인 요소는 _.flatten() 함수에 다시 집어넣어서 돌린다. 평탄화가 끝날 때까지 계속 돌다가 배열 속 배열이 다 없어지면 else가 성립하지 않아 재귀가 끝나고 result를 반환한다.
두 번째 방식은
_.flatten = function(nestedArray, result) {
result = [];
_.each(nestedArray, function(element) {
if (!Array.isArray(element)) result.push(element);
else if (Array.isArray(element)) {
result = result.concat(_.flatten(element));
}
})
return result;
};
비슷하지만 처음에 배열 속에 배열이 있는지 확인하는 과정을 안 거친다. 조금 더 효율적이길..
처음부터 훑으면서 배열이 아닌 요소는 result에 밀어넣고 배열인 요소는 _flatten 속으로 다시 들어간다.
함수를 썼다는 것 자체보다도 debugger를 사용해서 문제를 해결했다는 점이 뿌듯했다. 처음으로 써봤는데 함수가 돌아가는 과정을 들여다볼 수 있어서, 문제를 눈으로 확인할 수 있어서 코드를 고치는 게 한층 수월했다.
이를테면 중간에 result = [a]인 상황에서 다음 _.flatten이 돌아갔을 때 [b]가 붙어서 result = [a, b]로 나와야 하는데 result = [a, a, b]로 나오는 문제가 발생했다. 기존 result에 단순히 붙는 게 아니라 붙은 결과물이 기존 result에 붙는 것이었다.
그런데 debugger를 코드에 넣어서 과정을 살펴보니 문제가 발생하는 지점을 알 수 있어서 고칠 수 있었다. 처음에
result = result || [];
라고 쓴 게 문제였다.
어쨌든 이젠 처음에 시도했던 대로 _.reduce를 사용해서 _.flatten을 써보려 한다.
'TIL' 카테고리의 다른 글
Closure의 양면성 ft. 재귀함수 [자바스크립트] (0) | 2020.07.25 |
---|---|
TypeError가 날 때 간단한 debugger 활용 방법 [자바스크립트] (0) | 2020.07.24 |
_.every() | Lodash [자바스크립트] (0) | 2020.07.18 |
Array-like Object 처리, Array.prototype.slice.call() Array.from() 등[자바스크립트] (0) | 2020.07.13 |
_.reduce _.contains | Lodash [자바스크립트] (0) | 2020.07.11 |