Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

JavaScript 객체 속성을 기준으로 배열의 고유 요소 개수 구하는 방법

JavaScript를 다루다 보면 객체 배열 안에 특정 속성 값이 몇 종류나 존재하는지, 즉 고유(unique)한 값의 개수를 세어야 하는 경우가 자주 있습니다. 예를 들어 식당 주문 데이터가 담긴 다음과 같은 객체 배열이 있다고 가정해 보겠습니다.

const orders = [
    {table_id: 3, food_id: 5},
    {table_id: 4, food_id: 2},
    {table_id: 1, food_id: 6},
    {table_id: 3, food_id: 4},
    {table_id: 4, food_id: 6},
];

이 배열에는 각 주문이 어느 테이블(table_id)에서 어떤 음식(food_id)을 주문했는지에 대한 정보가 담겨 있습니다. 여기서 우리가 구하고자 하는 것은 다음 두 가지입니다.

  • 고유한 테이블 수 — 중복을 제외한 table_id 값이 총 몇 개인지
  • 고유한 메뉴 수 — 중복을 제외한 food_id 값이 총 몇 개인지

위 데이터를 기준으로 살펴보면, 테이블은 1, 3, 4번으로 총 3개이며, 음식은 5, 2, 6, 4번으로 총 4개입니다. 이제 이 값을 자동으로 계산해 주는 함수를 작성해 보겠습니다.

구현 방법

핵심 아이디어는 간단합니다. 배열을 순회하면서 각 속성 값을 임시 객체의 키(key)로 저장하면, JavaScript 객체는 동일한 키를 중복으로 가질 수 없기 때문에 자연스럽게 중복이 제거됩니다. 이후 Object.keys()로 키의 개수를 세면 곧 고유 값의 개수가 됩니다.

const orders = [
    {table_id: 3, food_id: 5},
    {table_id: 4, food_id: 2},
    {table_id: 1, food_id: 6},
    {table_id: 3, food_id: 4},
    {table_id: 4, food_id: 6},
];

const countUniques = (orders = []) => {
    const tableObj = {}, foodObj = {};

    orders.forEach(el => {
        tableObj[el.table_id] = null;
        foodObj[el.food_id] = null;
    });

    const tableUniqueIDs = Object.keys(tableObj).length;
    const foodUniqueIDs = Object.keys(foodObj).length;

    return {
        tableUniqueIDs,
        foodUniqueIDs
    };
};

console.log(countUniques(orders));

실행 결과

코드를 실행하면 콘솔에 아래와 같은 결과가 출력됩니다.

{ tableUniqueIDs: 3, foodUniqueIDs: 4 }

결과를 해석해 보면, 주문이 발생한 고유한 테이블은 3개(1, 3, 4번)이고, 주문된 고유한 음식은 4종(2, 4, 5, 6번)이라는 의미입니다.

Set을 활용한 대안

객체 대신 ES6의 Set 자료구조를 사용하면 코드를 더욱 간결하게 만들 수 있습니다. Set은 중복을 허용하지 않으므로 별도의 임시 객체 없이 바로 고유 값의 개수를 얻을 수 있습니다.

const countUniquesWithSet = (orders = []) => ({
    tableUniqueIDs: new Set(orders.map(el => el.table_id)).size,
    foodUniqueIDs: new Set(orders.map(el => el.food_id)).size
});

console.log(countUniquesWithSet(orders)); // { tableUniqueIDs: 3, foodUniqueIDs: 4 }

두 방법 모두 시간 복잡도는 O(n)으로 동일하지만, Set을 활용한 방식이 코드가 더 짧고 의도도 명확하게 드러나므로 최신 JavaScript 환경에서는 후자를 권장합니다.