Как использовать метод Reduce для массива объектов, чтобы создать отдельный объект с суммарными значениями для каждого?

1

Я пытаюсь использовать метод reduce на массиве объектов, каждый из которых является человеком и ароматом мороженого, которое им нравится. Цель состоит в том, чтобы уменьшить этот массив до одного объекта, который содержит ароматы как свойства и общее количество раз, когда аромат указан как значения.

данные:

const data = [
     { name: 'Tyler', favoriteIceCreams: ['Strawberry', 'Vanilla', 'Chocolate', 'Cookies & Cream'] },
     { name: 'Richard', favoriteIceCreams: ['Cookies & Cream', 'Mint Chocolate Chip', 'Chocolate', 'Vanilla'] },
     { name: 'Amanda', favoriteIceCreams: ['Chocolate', 'Rocky Road', 'Pistachio', 'Banana'] },
     { name: 'Andrew', favoriteIceCreams: ['Vanilla', 'Chocolate', 'Mint Chocolate Chip'] },
     { name: 'David', favoriteIceCreams: ['Vanilla', 'French Vanilla', 'Vanilla Bean', 'Strawberry'] },
     { name: 'Karl', favoriteIceCreams: ['Strawberry', 'Chocolate', 'Mint Chocolate Chip'] }
 ];

Это то, что у меня есть до сих пор, но я честно не знаю, как это сделать.

let iceCreamTotals = {
         Strawberry: 0,
         Vanilla: 0,
         Chocolate: 0,
         CookiesCream: 0,
         MintChocolateChip: 0,
         RockyRoad: 0,
         Pistachio: 0,
         Banana: 0,
         FrenchVanilla: 0,
         VanillaBean: 0
     }

     data.reduce((total, current) => {

         return iceCreamTotals
     }, 0)
Теги:

4 ответа

1
Лучший ответ

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

var data = [
     { name: 'Tyler', favoriteIceCreams: ['Strawberry', 'Vanilla', 'Chocolate', 'Cookies & Cream'] },
     { name: 'Richard', favoriteIceCreams: ['Cookies & Cream', 'Mint Chocolate Chip', 'Chocolate', 'Vanilla'] },
     { name: 'Amanda', favoriteIceCreams: ['Chocolate', 'Rocky Road', 'Pistachio', 'Banana'] },
     { name: 'Andrew', favoriteIceCreams: ['Vanilla', 'Chocolate', 'Mint Chocolate Chip'] },
     { name: 'David', favoriteIceCreams: ['Vanilla', 'French Vanilla', 'Vanilla Bean', 'Strawberry'] },
     { name: 'Karl', favoriteIceCreams: ['Strawberry', 'Chocolate', 'Mint Chocolate Chip'] }
 ];
 
 var flavours = data.reduce(function(acc, obj) {
  // for each flavour, add it to the accumulator if it not already there
  // and increament its count
  obj.favoriteIceCreams.forEach(function(flavour) {
    if (!acc[flavour]) {
      acc[flavour] = 0;
    }
    ++acc[flavour];
  });
  return acc;
}, Object.create(null));
 
console.log(flavours);
3

reduce this array into a single object, поэтому аккумулятор (второй аргумент для reduce, необязательный) должен быть объектом. Затем на каждом шаге подсчитайте соответствующее свойство для каждого элемента массива (c.favoriteIceCreams.forEach). p[cream] = (p[cream] || 0) + 1; это просто синтаксический сахар для "добавить один, если он существует в противном случае, равным 0 + 1".

const data = [
     { name: 'Tyler', favoriteIceCreams: ['Strawberry', 'Vanilla', 'Chocolate', 'Cookies & Cream'] },
     { name: 'Richard', favoriteIceCreams: ['Cookies & Cream', 'Mint Chocolate Chip', 'Chocolate', 'Vanilla'] },
     { name: 'Amanda', favoriteIceCreams: ['Chocolate', 'Rocky Road', 'Pistachio', 'Banana'] },
     { name: 'Andrew', favoriteIceCreams: ['Vanilla', 'Chocolate', 'Mint Chocolate Chip'] },
     { name: 'David', favoriteIceCreams: ['Vanilla', 'French Vanilla', 'Vanilla Bean', 'Strawberry'] },
     { name: 'Karl', favoriteIceCreams: ['Strawberry', 'Chocolate', 'Mint Chocolate Chip'] }
 ];
 
 console.log(data.reduce((p, c) => {
  c.favoriteIceCreams.forEach(cream => {
    p[cream] = (p[cream] || 0) + 1;
  });
  return p;
 }, {}));
  • 0
    Вы можете уменьшить (p[cream] || 0) + 1 до ++p[cream] || 1 , но это может быть немного запутанным.
  • 1
    @RobG Да, или ~~p[cream] + 1 :)
0

Ваша проблема имеет два аспекта. Первый собирает все вкусы со всех людей. Второй - подсчет частоты каждого аромата. Ваш код будет проще и легче отлаживать и более читабельным, если вы выделите эти два аспекта. Собирать все вкусы просто

const flavors = [].concat(...data.map(({favoriteIceCreams}) => favoriteIceCreams));

Или, если вы предпочитаете:

const flavors = [];

for (const {favoriteIceCreams} of data) flavors.push(...favoriteIceCreams);

На SO есть много решений о подсчете частоты появления в массиве. Подумайте об этом.

0

Вы можете использовать for..of loop, Object.hasOwnProperty() чтобы проверить, установлено ли свойство на объекте, если значение истинного инкремента, иначе заданное значение равно 0

let res = {}
for (let {favoriteIceCreams} of data) 
  for (let iceCream of favoriteIceCreams) 
    res[iceCream] = res.hasOwnProperty(iceCream) ? ++res[iceCream] : 1;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню