ES2015 + способ эффективного преобразования массива объектов в сгруппированную хэш-карту с массивом объектов в качестве значения - PullRequest
0 голосов
/ 22 апреля 2019

Я пытаюсь найти элегантный и эффективный способ преобразования массива объектов в объект, индексированный по ключу (в данном случае «groupByThisKey»). Хэш-карта, я думаю, это называется.

Я смог придумать примитивную версию

Объясняется некоторыми данными ниже:

const arr = [
  {
    id: 1,
    name: "one",
    groupByThisKey: 'groupA'
  },
  {
    id: 2,
    name: "two",
    groupByThisKey: 'groupB'
  },
  {
    id: 3,
    name: "three",
    groupByThisKey: 'groupB'
  },
  {
    id: 4,
    name: "four",
    groupByThisKey: 'groupA'
  }
];

const groupedByKey = {};

arr.map(obj => {
  if (groupedByKey[obj.groupByThisKey])
    groupedByKey[obj.groupByThisKey].push(obj)
  else
    groupedByKey[obj.groupByThisKey] = [obj]
});

console.log(groupedByKey)

Это дает желаемый результат:

{
  groupA: [
   {
     id: 1,
     name: "one",
     groupByThisKey: 'groupA'
   },
   {
     id: 4,
     name: "four",
     groupByThisKey: 'groupA'
   }
  ],
  groupB: [
   {
     id: 2,
     name: "two",
     groupByThisKey: 'groupB'
   },
   {
     id: 3,
     name: "three",
     groupByThisKey: 'groupB'
   }
  ]
}

Но довольно примитивно. Я бы предпочел использовать более короткий и более современный способ сделать это, возможно, с помощью object.assign или Reduce, если это возможно, но не могу обернуться вокруг него, поскольку мне нужен массив значений для каждого ключа.

Мне удалось найти много примеров, которые, казалось бы, работали для случаев использования, когда у вас есть только одно значение на ключ, но в моем случае мне понадобился бы массив объектов, сгруппированных по этому ключу , поэтому примеры, которые я нашел, будут только самые последние. Вот пример:

const hash = Object.assign({}, ...array.map(s => ({[s.key]: s.value})));

Ответы [ 2 ]

1 голос
/ 22 апреля 2019

То, что вы реализовали, довольно правильно, позвольте мне убрать побочные эффекты, используя редуктор:

const arr = [
  {
    id: 1,
    name: "one",
    groupByThisKey: 'groupA'
  },
  {
    id: 2,
    name: "two",
    groupByThisKey: 'groupB'
  },
  {
    id: 3,
    name: "three",
    groupByThisKey: 'groupB'
  },
  {
    id: 4,
    name: "four",
    groupByThisKey: 'groupA'
  }
];

console.log(arr.reduce((groupedByKey,obj) => {
  if (groupedByKey[obj.groupByThisKey])
    groupedByKey[obj.groupByThisKey].push(obj)
  else
    groupedByKey[obj.groupByThisKey] = [obj]
    
  return groupedByKey;
}, {}));

Здесь вы найдете самый fp-ish способ написания.Не очень эффективно, следующая версия ниже (после этого) будет иметь лучшую производительность, потому что это не новое создание объектов или массивов на самой итерации.

const arr = [
    {
        id: 1,
        name: "one",
        groupByThisKey: 'groupA'
    },
    {
        id: 2,
        name: "two",
        groupByThisKey: 'groupB'
    },
    {
        id: 3,
        name: "three",
        groupByThisKey: 'groupB'
    },
    {
        id: 4,
        name: "four",
        groupByThisKey: 'groupA'
    }
];

console.log(arr.reduce(
    (groups, x) => 
        ({ 
            ...groups, 
            [x.groupByThisKey]: [
                ...(groups[x.groupByThisKey] || []),
                x
            ]
        })
    , {}
))

Упрощенная версия, которая имеет ту же логику, что и выше:

const arr = [
    {
        id: 1,
        name: "one",
        groupByThisKey: 'groupA'
    },
    {
        id: 2,
        name: "two",
        groupByThisKey: 'groupB'
    },
    {
        id: 3,
        name: "three",
        groupByThisKey: 'groupB'
    },
    {
        id: 4,
        name: "four",
        groupByThisKey: 'groupA'
    }
];

console.log(arr.reduce(
    (groups, x) => {
        let key = x.groupByThisKey;
        
        if (groups[key] === undefined)
            groups[key] = [];
            
        groups[key].push(x);
        
        return groups;
    }, {}
))
1 голос
/ 22 апреля 2019

Современный способ будет использовать Map, а не объект:

const groupedByKey = new Map();
for (const obj of arr) {
  if (!groupedByKey.has(obj.groupByThisKey))
    groupedByKey.set(obj.groupByThisKey, []);
  groupedByKey.get(obj.groupByThisKey).push(obj);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...