将对象数组中的所有数据求和到新的对象数组中

时间:2018-09-24 12:09:15

标签: javascript arrays lodash

我有一个看起来像这样的对象数组:

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

我想对数组中的每个元素求和以产生这样的数组:

var result = [{costOfAirtickets: 4000, costOfHotel: 3200}]

我使用了map和reduce函数,但是我只能像这样对单个元素求和:

data.map(item => ite.costOfAirtickets).reduce((prev, next)=>prev + next); // 22

目前,这会产生一个单一值,根据初始说明,这不是我想要的。

有没有办法用Javascript或可能是lodash来做到这一点。

14 个答案:

答案 0 :(得分:16)

使用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)

答案 1 :(得分:7)

使用Lodash简化生活。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.pays</groupId>
    <artifactId>pays</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>pays</name>

    <properties>
        <org.springframework.version>4.3.19.RELEASE</org.springframework.version>       
        <spring.ws.version>2.2.0.RELEASE</spring.ws.version>
        <apache.wss4j.version>1.6.18</apache.wss4j.version>
        <org.slf4j-version>1.7.5</org.slf4j-version>
        <org.springframework.security.version>3.2.4.RELEASE</org.springframework.security.version>

        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jackson.library>2.9.5</jackson.library>
        <logback.version>1.2.3</logback.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <context.path>pays</context.path>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.ws.security</groupId>
            <artifactId>wss4j</artifactId>
            <version>${apache.wss4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>${spring.ws.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-security</artifactId>
            <version>${spring.ws.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.santuario/xmlsec -->
        <dependency>
            <groupId>org.apache.santuario</groupId>
            <artifactId>xmlsec</artifactId>
            <version>2.0.9</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.6</version>
            <type>jar</type>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.6</version>
            <type>jar</type>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <!-- Dependencias de Swagger -->  
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>         
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.13.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <generatePackage>com.pays.generated</generatePackage>
                    <generateDirectory>${project.basedir}/src/main/java</generateDirectory>
                    <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
                    <schemaIncludes>
                        <include>*.wsdl</include>
                    </schemaIncludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <warName>${context.path}</warName>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

说明:

  • const _ = require('lodash') let keys = ['costOfAirtickets', 'costOfHotel']; let results = _.zipObject(keys, keys.map(key => _.sum( _.map(data, key)))) ... { costOfAirtickets: 4000, costOfHotel: 2200 } :生成每个数组的总和
  • _.sum(_.map(data, key)):使用数组sum压缩结果
  • 对每个密钥的总和使用_.zipObject作为keys.map()不能保证顺序。

文档:

答案 2 :(得分:4)

要创建结果值/减少值,应使用.reduce()方法而不是.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);

答案 3 :(得分:4)

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

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

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

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

答案 4 :(得分:4)

这是一种lodash方法

_(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 1)).value()

它将通过所有唯一键求和。

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

var res = _(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 0)).value();

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

将结果包装到[...]或在末尾使用.castArray(),然后再用.value()展开,以防需要数组作为结果。

答案 5 :(得分:4)

另一种解决方案是使用Map(不是Array.prototype.map ),因为它有多个notable differences compared to objects

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())

说明

外循环

以上方法首先使用data方法遍历reduce数组。我将其中的每个对象都称为一条记录-在代码中通过变量rcd进行了区分。

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

内循环

reduce循环中,使用forEach遍历记录的每个键/值对。要获取键/值对,请使用Object.entries方法。使用数组解构,这些参数可以直接分配给相应的变量keyvalue

获取/设置值

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

地图替代品

如果您发现 Map 有点笨拙,则还可以使用类似Set的类似对象,它具有许多相同的方法({{1}除外}),也可以使用原始对象(即get())。

答案 6 :(得分:1)

您可以为此使用简单的forEach()循环:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var res = [];
var tempObj = {};
data.forEach(({costOfAirtickets, costOfHotel}) => {
  tempObj['costOfAirtickets'] = (tempObj['costOfAirtickets'] || 0) + costOfAirtickets;
  tempObj['costOfHotel'] = (tempObj['costOfHotel'] || 0) + costOfHotel;
 });
res.push(tempObj);
console.log(res);

答案 7 :(得分:1)

仅按以下代码段尝试使用reduce。尝试避免多次迭代。希望下面的代码片段有帮助!

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

var total = data.reduce(function (result,value,key) {
result['costOfAirtickets'] = result['costOfAirtickets']  + value['costOfAirtickets'];
result['costOfHotel'] = result['costOfHotel']  + value['costOfHotel'];

return result},{costOfAirtickets:0,costOfHotel:0});

console.log(total)

答案 8 :(得分:1)

您可以通过取一个对象求和来减少数组。

var data = [{ costOfAirtickets: 2500, costOfHotel: 1200 }, { costOfAirtickets: 1500, costOfHotel: 1000 }],
    keys = ['costOfAirtickets', 'costOfHotel'],
    sum = data.reduce((r, o) => {
        keys.forEach(k => r[k] += o[k]);
        return r;
    }, Object.assign(...keys.map(k => ({ [k]: 0 }))));

console.log(sum);

答案 9 :(得分:1)

map对象并计算总和并将其存储在另一个对象中。

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var result = [];
var sum = 0;
var costsum = 0;
data.map(function(item, key){
  var cost = item;
  //nsole.log(cost);
  sum = sum + cost.costOfAirtickets;
  costsum = costsum + cost.costOfHotel;

});

result = [{costOfAirtickets:sum, costOfHotel:costsum}];

console.log(result);

答案 10 :(得分:1)

这是我能想到的最简单的方法

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var sum ={};
for(var obj in data){
  for(var ele in data[obj]){
    if(!data[obj].hasOwnProperty(ele)) continue;
      if(sum[ele] === undefined){
        sum[ele] = data[obj][ele];
      }else{
        sum[ele] = sum[ele] + data[obj][ele];
      }
  }

}
var arr = [sum];
console.log(arr);

答案 11 :(得分:1)

我的答案很简单;

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},
            {costOfAirtickets: 1500, costOfHotel: 1000}],
    res  = data.reduce((p,c) => Object.entries(c).reduce((r,[k,v]) => (r[k]+=v, r), p));
console.log(res);

使用.reduce()的注意事项:如果数组项和累加值是同一类型,则您可以考虑不使用初始值作为累加器,而使用上一个(p和当前(c)元素。上面代码段中的外部reduce就是这种类型。但是,内部reduce将一组键(k)值(v)对作为[k,v]对来返回对象,因此初始值(p)是必不可少的。

结果是作为对象的累加值。如果需要将其放在数组中,则只需将其放在类似[res]的数组中即可。

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

Lodash

分别使用lodash reduce_.mergeWith

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

var result = _.reduce(data, (r,c) => _.mergeWith(r, c, (o = 0, s) => o + s), {})

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

仅ES6

如果您不想突变,则可以使用ES6 reduceObject.entriesforEach,如下所示:

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

// One liner
var result1 = data.reduce((r, c) =>
  !Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value) && r, {})

// More readable
var result2 = data.reduce((r, c) => {
  Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value)
  return r
}, {})

console.log(result1)
console.log(result2)

如果我们不关心初始data数组的变异,那么我们可以采用一个线性解决方案:

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

data.reduce((r, c) => !Object.entries(c).forEach(([key,value]) => r[key] += value) && r)

console.log(data[0])

更具可读性:

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

data.reduce((r, c) => {
  Object.entries(c).forEach(([key, value]) => r[key] += value)
  return r
})

console.log(data[0])

变异示例和非变异示例之间的唯一区别是reduce初始值(以及事实是,在变异中,我们使用0索引作为累加器总和)。在变异变量中,没有initial value,而在其他变量中,我们以空对象字面量开头。

如果您需要将结果特别地设置为数组,则为变异示例返回[data],为纯示例返回[result]