将对象数组中的所有数据汇总到新的对象数组中

Dav*_*alu 26 javascript arrays lodash

我有一个对象数组,如下所示:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}]
Run Code Online (Sandbox Code Playgroud)

我想对数组中的每个元素求和,以产生如下数组:

var result = [{costOfAirtickets: 4000, costOfHotel: 3200}]
Run Code Online (Sandbox Code Playgroud)

我使用了map和reduce函数,但我只能将一个单独的元素求和:

data.map(item => ite.costOfAirtickets).reduce((prev, next)=>prev + next); // 22
Run Code Online (Sandbox Code Playgroud)

目前这产生了一个单独的值,这不是我想要的初始解释.

有没有办法在Javascript或可能与lodash这样做.

Chr*_* Li 17

使用for..in迭代对象和reduce迭代阵列

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];

var result = [data.reduce((acc, n) => {
  for (var prop in n) {
    if (acc.hasOwnProperty(prop)) acc[prop] += n[prop];
    else acc[prop] = n[prop];
  }
  return acc;
}, {})]
console.log(result)
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案很不错,因为它允许每个行程自动包含不同的属性(`{...,costOfRentalCar:300}`).但它只适用于旅行中的*only*属性是成本. (2认同)
  • 而不是`acc [prop]`,使用[`acc.hasOwnProperty(prop)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty).这可以防止在某些情况下检查是否存在`__toString`或其他内容.另外,使用`acc [prop] + = + n [prop] || 0;`用于求和.如果我将一个字符串传递给它,它将只是连接.`+ n [prop]`强制它转换为整数.`|| 0`删除其他虚假值,如NaN.同样的事情`acc [prop] = n [prop]`是`acc [prop] = + n [prop] || 0`. (2认同)
  • 这个答案已经过时了几年。人们不再使用 `for...in` + `hasOwnProperty`,而是使用 `for(const key of Object.keys(...))`。此外,这整个事情可以使用 lodash 以简单的单行方式完成。 (2认同)

Roo*_*iat 7

使用Lodash简化您的生活.

const _ = require('lodash')
let keys = ['costOfAirtickets', 'costOfHotel']; 
let results = _.zipObject(keys, keys.map(key => _.sum( _.map(data, key))))
...
{ costOfAirtickets: 4000, costOfHotel: 2200 }
Run Code Online (Sandbox Code Playgroud)

说明:

  • _.sum(_.map(data, key)):生成每个数组的总和
  • _.zipObject:使用数组和来压缩结果
  • 使用keys.map()每个密钥的总和,因为_.map不保证订单.

文档:

  • 很想知道downvote的原因. (3认同)
  • @DaveKalu:为什么?结果直接包含要求的值。你不是OP吗?IMO这是最好的答案。@Roopak:您仍然可以简化一下:_.sumBy(data,key)或__data.sumBy(key)。 (2认同)
  • @DaveKalu:这确实解决了所问的确切问题。这也是这个页面上最干净的答案,正是我要写的。注意`keys`可以定义为`const keys = Object.keys(data);` (2认同)

小智 6

您不需要映射数组,您实际上只是在减少其中的内容。

const totalCostOfAirTickets: data.reduce((prev, next) => prev + next.costOfAirTickets, 0)
const totalCostOfHotel: data.reduce((prev, next) => prev + next.costOfHotel, 0)
const totals = [{totalCostOfAirTickets, totalCostOfHotel}]
Run Code Online (Sandbox Code Playgroud)

一口气,你可以做类似的事情

const totals = data.reduce((prev, next) => { 
    prev.costOfAirTickets += next.costOfAirTickets; 
    prev.costOfHotel += next.costOfHotel; 
}, {costOfAirTickets: 0, costOfHotel: 0})
Run Code Online (Sandbox Code Playgroud)


Moh*_*man 5

要创建一个结果值/减少值,您应该使用.reduce()method而不是.map()

let data = [
  {costOfAirtickets: 2500, costOfHotel: 1200},
  {costOfAirtickets: 1500, costOfHotel: 1000}
];

let result = data.reduce(
  (a, c) => (Object.keys(c).forEach(k => (a[k] = (a[k] || 0) + c[k])), a), {}
);

console.log(result);
Run Code Online (Sandbox Code Playgroud)


Mik*_*ike 5

另一种解决方案是使用Map而不是 Array.prototype.map),因为它与对象相比有几个显着差异

var data = [{
  costOfAirtickets: 2500,
  costOfHotel: 1200
}, {
  costOfAirtickets: 1500,
  costOfHotel: 1000
}]

let sums = data.reduce((collection,rcd)=>{
  Object.entries(rcd).forEach(([key,value])=>{
      let sum = collection.get(key) || 0
      collection.set(key, sum + +value)
  })
  return collection
}, new Map())

console.log(...sums.entries())
Run Code Online (Sandbox Code Playgroud)

解释

外环

上面首先data使用该reduce方法遍历您的数组。我将其中的每个对象称为记录——在代码中通过变量rcd.

reduce 的每次迭代都会返回一个值,该值作为第一个参数传递给循环的下一次迭代。在这种情况下,参数collection包含该参数,即您的总和集。

内循环

reduce循环中,记录的每个键/值对都使用 迭代forEachObject.entries使用该方法获取键/值对。使用数组解构这些参数可以直接分配给相应的变量,key并且value

检索/设置值

与原始对象不同,Map它有自己的方法来使用get()和获取和设置其条目set()。因此,首先使用 检索先前的总和get(),如果未设置,则默认为0,这就是它的|| 0作用。此时,您可以假设先前的总和至少为 0 或更大,并将当前键的值添加到其上。

地图的替代品

如果您发现Map有点笨手笨脚,您也可以使用类似的对象,例如Set,它具有许多相同的方法(除了get()),或者您也可以使用原始对象(即{})。