我有一个看起来像这样的对象数组:
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来做到这一点。
答案 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
方法。使用数组解构,这些参数可以直接分配给相应的变量key
和value
与原始对象不同,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 reduce,Object.entries和forEach,如下所示:
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]
。