문제 소개
다음과 같이 여러 개의 하위 배열을 포함하는 2차원 배열이 있다고 가정해 보겠습니다.
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
];이 배열을 입력받아, 모든 하위 배열에 공통으로 나타나는 문자열만 모아 하나의 배열로 반환하는 JavaScript 함수를 작성해야 합니다.
해결 방법: reduce()와 filter() 조합
이 문제는 Array.prototype.reduce() 메서드를 활용하면 간결하게 해결할 수 있습니다. 핵심 전략은 다음과 같습니다.
- 누적값(acc)을 첫 번째 하위 배열에서 시작합니다.
- 배열을 순회할 때마다 현재 하위 배열(val)에도 존재하는 요소만
filter()로 걸러냅니다. - 모든 순회가 끝난 후 남은 요소들이 곧 공통 문자열입니다.
예제 코드
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
];
const commonArray = arr => {
return arr.reduce((acc, val) => {
return acc.filter(el => val.indexOf(el) !== -1);
});
};
console.log(commonArray(arr));출력 결과
콘솔 출력 결과는 다음과 같습니다.
['bar']
동작 원리
코드가 실행되는 과정을 단계별로 살펴보면 다음과 같습니다.
- 1단계: acc = ['foo', 'bar', 'hey', 'oi'] → 두 번째 배열과 비교하여 ['foo', 'bar', 'hey']만 남습니다.
- 2단계: 세 번째 배열과 비교하여 ['foo', 'bar']만 남습니다.
- 3단계: 네 번째 배열과 비교하여 최종적으로 ['bar']만 남습니다.
이처럼 reduce와 filter를 조합하면 별도의 반복문 없이 선언적인 방식으로 공통 요소를 손쉽게 구할 수 있습니다. 참고로 ES2016부터 지원되는 Array.prototype.includes()를 활용해 val.indexOf(el) !== -1 대신 val.includes(el)로 작성하면 코드의 가독성을 더욱 높일 수 있습니다.