javascript - 使用 .reduce 函数进行某些计算并返回带有数组结果的对象

标签 javascript arrays json reduce

所以我已经成功地得到了我想要的结果:

const days = [
{
    date: '2016-12-13T00:00:00.000Z',
    stats: [
      { name: 'Soft Drinks', sold: 34, },
      { name: 'Snacks', sold: 3, },
      { name: 'Coffee and warm drinks', sold: 26, },
    ],
  },
  {
    date: '2016-12-14T00:00:00.000Z',
    stats: [
      { name: 'Soft Drinks', sold: 34, },
      
      { name: 'Snacks', sold: 3, },
      { name: 'Coffee and warm drinks', sold: 26, },
    ],
  },
];

const newStats = days.reduce(function (pastDay, currentDay) {
  const nextStats = currentDay.stats.map(function(stat) {
  	const oldSold = pastDay.stats.find(function (old) {
    	return old.name === stat.name;
    });
    
  	const newSold = stat.sold + oldSold.sold;
  	stat.sold = newSold;
    return stat;
  });

  return {
    stats: nextStats,
  };
});

console.log(newStats);

输出:

{
  "stats": [
    {
      "name": "Soft Drinks",
      "sold": 68
    },
    {
      "name": "Snacks",
      "sold": 6
    },
    {
      "name": "Coffee and warm drinks",
      "sold": 52
    }
  ]
}

这正是我所追求的,但是在处理不同的日期数组时,它遵循相同的对象数组结构。我在 pastDay 收到未定义的错误,任何人都可以帮助我发现问题吗?或者帮我找到 .reduce

的替代方案

我遇到问题的数组:

const days = [  
   {  
      "_id":{  
         "_str":"f23f02994ab992437e423e24"
      },
      "date":"2016-12-13T00:00:00.000Z",
      "statistics":{  
         "breakdown":{  
            "byTurnover":[  
               {  
                  "name":"Soft Drinks",
                  "sold":34,
                  "percentage":31.14
               },
               {  
                  "name":"Snacks",
                  "sold":3,
                  "percentage":2.65
               },
               {  
                  "name":"Coffee and warm drinks",
                  "sold":26,
                  "percentage":21.54
               },
               {  
                  "name":"Brandy",
                  "sold":2,
                  "percentage":2.75
               },
               {  
                  "name":"Beer",
                  "sold":20,
                  "percentage":20.15
               },
               {  
                  "name":"Mixed drinks Other",
                  "sold":21,
                  "percentage":21.77
               }
            ],
         }
      },
      "id":{  
         "_str":"f23f02994ab992437e423e24"
      }
   },
   {  
      "_id":{  
         "_str":"b3d0ad7f314e33021739f70c"
      },
      "date":"2016-12-14T00:00:00.000Z",
      "statistics":{  
         "breakdown":{  
            "byTurnover":[  
               {  
                  "name":"Soft Drinks",
                  "sold":34,
                  "percentage":31.14
               },
               {  
                  "name":"Snacks",
                  "sold":3,
                  "percentage":2.65
               },
               {  
                  "name":"Coffee and warm drinks",
                  "sold":26,
                  "percentage":21.54
               },
               {  
                  "name":"Brandy",
                  "sold":2,
                  "percentage":2.75
               },
               {  
                  "name":"Beer",
                  "sold":20,
                  "percentage":20.15
               },
               {  
                  "name":"Mixed drinks Other",
                  "sold":21,
                  "percentage":21.77
               }
            ],
         }
      },
      "id":{  
         "_str":"b3d0ad7f314e33021739f70c"
      }
   },
   {  
      "_id":{  
         "_str":"e1906ce07ab811c74528e3cc"
      },
      "date":"2016-12-15T00:00:00.000Z",
      "statistics":{  
         "breakdown":{  
            "byTurnover":[  
               {  
                  "name":"Soft Drinks",
                  "sold":34,
                  "percentage":31.14
               },
               {  
                  "name":"Snacks",
                  "sold":3,
                  "percentage":2.65
               },
               {  
                  "name":"Coffee and warm drinks",
                  "sold":26,
                  "percentage":21.54
               },
               {  
                  "name":"Brandy",
                  "sold":2,
                  "percentage":2.75
               },
               {  
                  "name":"Beer",
                  "sold":20,
                  "percentage":20.15
               },
               {  
                  "name":"Mixed drinks Other",
                  "sold":21,
                  "percentage":21.77
               }
            ],
         }
      },
      "id":{  
         "_str":"e1906ce07ab811c74528e3cc"
      }
   },
];

const newStats = days.reduce(function (pastDay, currentDay) {
  const nextStats = currentDay.statistics.breakdown.byTurnover.map(function(stat) {
  	const oldSold = pastDay.statistics.breakdown.byTurnover.find(function (old) {
    	return old.name === stat.name;
    });
    
  	const newSold = stat.sold + oldSold.sold;
  	stat.sold = newSold;
    return stat;
  });

  return {
    stats: nextStats,
  };
});

console.log(newStats);

输出:未捕获类型错误:无法读取未定义的属性“分解”

第二个数组的 .reduce 代码:

const newStats = days.reduce(function (pastDay, currentDay) {
  const nextStats = currentDay.statistics.breakdown.byTurnover.map(function(stat) {
    const oldSold = pastDay.statistics.breakdown.byTurnover.find(function (old) {
        return old.name === stat.name;
    });

    const newSold = stat.sold + oldSold.sold;
    stat.sold = newSold;
    return stat;
  });

  return {
    stats: nextStats,
  };
});

console.log(newStats);

最佳答案

您的第一个 reducer 正在返回与输入数组匹配的对象格式,如下所示

return {
    stats: nextStats,
};

你的数组看起来像:

const days = [{ stats: [...] }]

因此,当您的内部循环将 .stats 作为数组进行迭代时,它将正确运行。

您的第二个 reducer 正在迭代具有以下结构的对象:

const days = [{ statistics: { breakdown: { byTurnover: [...] } }]

但随后返回一个与该结构不匹配的对象:

return {
    stats: nextStats,
};

因此,reducer 的第一次迭代将起作用,然后第二次迭代将运行,第一个参数 pastDay 将是上一次运行的返回值,其中不会有任何您正在查找的键。

一个快速而肮脏的解决方案是在返回时匹配对象键深度:

const newStats = days.reduce(function (pastDay, currentDay) {
    const nextStats = currentDay.statistics.breakdown.byTurnover.map(function(stat) {
        const oldSold = pastDay.statistics.breakdown.byTurnover.find(function (old) {
            return old.name === stat.name;
        });

        const newSold = stat.sold + oldSold.sold;
        stat.sold = newSold;
        return stat;
    });

    return {
        statistics: { breakdown: { byTurnover: nextStats } },
    };
});

虽然这回答了问题,但您使用的逻辑很难遵循。根据您想要完成的任务(代码中不清楚),这可能不是一个理想的方法。

关于javascript - 使用 .reduce 函数进行某些计算并返回带有数组结果的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41132489/

相关文章:

json - 从 JSON 获取数据时遇到问题

java - 如何按升序对从 java 端点获取的 JSON 响应进行排序

java - 将Java Map对象转换为Json数组

javascript - 选择文件后立即通过 AJAX 上传文件

java - 使用循环以类似Python的方式连接Java中的数组元素

javascript - 我试图通过编写回调来使 "merge function"工作。

c++ - 比较c++中的两个数组并根据元素的匹配或不匹配返回值

python - 在 numpy/scipy 中从 3D 矩阵堆栈构造 3D block 对角矩阵堆栈的有效方法

javascript - 验证输入框中的所有条目

php - 如何从字符串输出中删除回车符?