문제 상황
다음과 같은 객체 배열이 있다고 가정해 보겠습니다.
const arr = [
{area: 'NY', name: 'Bla', ads: true},
{area: 'DF', name: 'SFS', ads: false},
{area: 'TT', name: 'SDSD', ads: true},
{area: 'SD', name: 'Engine', ads: false},
{area: 'NSK', name: 'Toyota', ads: false},
];여기서 우리는 첫 번째 인수로 위와 같은 객체 배열을, 두 번째 인수로 문자열 리터럴 배열을 받는 JavaScript 함수를 작성해야 합니다.
이 함수는 각 객체의 area 속성 값이 두 번째 인수로 전달된 문자열 배열에 포함되어 있는 경우에만 해당 객체를 유지하도록 원본 배열을 필터링한 결과를 반환해야 합니다.
예제: for 루프를 사용한 구현
가장 기본적인 방식인 for 루프를 사용하여 작성한 코드는 다음과 같습니다.
const arr = [
{area: 'NY', name: 'Bla', ads: true},
{area: 'DF', name: 'SFS', ads: false},
{area: 'TT', name: 'SDSD', ads: true},
{area: 'SD', name: 'Engine', ads: false},
{area: 'NSK', name: 'Toyota', ads: false},
];
const keys = ['NY', 'SD'];
const filterByArea = (arr = [], keys = []) => {
const res = [];
for(let i = 0; i < arr.length; i++){
const { area } = arr[i];
if(keys.includes(area)){
res.push(arr[i]);
};
};
return res;
};
console.log(filterByArea(arr, keys));출력 결과
콘솔에 출력되는 결과는 다음과 같습니다.
[
{ area: 'NY', name: 'Bla', ads: true },
{ area: 'SD', name: 'Engine', ads: false }
]예상대로 area 값이 'NY' 또는 'SD'인 객체만 결과 배열에 포함된 것을 확인할 수 있습니다.
더 간결한 방법: filter() 메서드 활용
위 구현은 정확하지만 다소 장황합니다. ES6에서 도입된 Array.prototype.filter() 메서드와 includes()를 조합하면 동일한 로직을 한 줄로 표현할 수 있습니다.
const filterByArea = (arr = [], keys = []) =>
arr.filter(({ area }) => keys.includes(area));
console.log(filterByArea(arr, keys));
// [{ area: 'NY', name: 'Bla', ads: true },
// { area: 'SD', name: 'Engine', ads: false }]구조 분해 할당({ area })을 통해 각 객체에서 필요한 속성만 꺼내고, 조건에 맞는 요소만 자동으로 걸러주므로 코드가 훨씬 읽기 쉬워집니다.
성능 팁: Set을 활용한 최적화
배열의 크기가 크거나 필터링 조건 목록이 길다면, includes()는 내부적으로 선형 탐색을 수행하기 때문에 O(n)의 시간이 걸립니다. 이 경우 Set으로 변환하면 조회가 O(1)로 개선됩니다.
const filterByArea = (arr = [], keys = []) => {
const keySet = new Set(keys);
return arr.filter(({ area }) => keySet.has(area));
};마무리
객체 배열을 다른 배열의 값을 기준으로 필터링할 때는 filter()와 includes()(또는 대량 데이터 처리 시 Set.has())를 조합하는 것이 가장 깔끔하고 효율적인 접근 방식입니다. 상황에 맞게 선택하여 사용하시기 바랍니다.