在对象数组中对具有相同对象属性 B 的 JavaScript 对象属性 A 值求和
Sum JavaScript object propertyA values with the same object propertyB in an array of objects
如何获取JavaScript对象数组,例如
objArr = [
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:42},
{key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
{key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23},
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:54} // <- duplicate key
]
并通过对值求和来合并重复的键?
为了得到这样的东西:
reducedObjArr = [
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:96},
{key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
{key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23}
]
我尝试迭代并添加到新数组,但这不起作用:
var reducedObjArr = [];
var item = null, key = null;
for(var i=0; i<objArr.length; i++) {
item = objArr[i];
key = Object.keys(item)[0];
item = item[key];
if(!result[key]) {
result[key] = item;
} else {
result[key] += item;
}
}a
与其使用 for 循环和推送值,不如直接使用 map 和 reduce:
let objArr = [
{key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42},
{key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78},
{key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23},
{key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}
];
// first, convert data into a Map with reduce
let counts = objArr.reduce((prev, curr) => {
let count = prev.get(curr.key) || 0;
prev.set(curr.key, curr.val + count);
return prev;
}, new Map());
// then, map your counts object back to an array
let reducedObjArr = [...counts].map(([key, value]) => {
return {key, value}
})
console.log(reducedObjArr);
每个未找到的对象分配给结果及其 .key
属性。
如果找到,则需要添加其.val
。
var temp = {};
var obj = null;
for(var i=0; i < objArr.length; i++) {
obj=objArr[i];
if(!temp[obj.key]) {
temp[obj.key] = obj;
} else {
temp[obj.key].val += obj.val;
}
}
var result = [];
for (var prop in temp)
result.push(temp[prop]);
另外,部分问题在于您重用item
变量来引用.key
的值,因此您丢失了对该对象的引用。
比其他地方发布更简单的reduce,因为它不使用Map元素
const objArr = [
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:42},
{key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
{key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23},
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:54}];
const output = objArr.reduce((accumulator, cur) => {
let date = cur.key;
let found = accumulator.find(elem => elem.key === date)
if (found) found.val += cur.val;
else accumulator.push(cur);
return accumulator;
}, []);
console.log(output)
您可以使用哈希表按key
进行分组。
var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}],
grouped = [];
array.forEach(function (o) {
if (!this[o.key]) {
this[o.key] = { key: o.key, val: 0 };
grouped.push(this[o.key]);
}
this[o.key].val += o.val;
}, Object.create(null));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
另一种方法是收集Map
中的所有键/值对,并使用Array.from
和对象的回调格式化最终数组。
var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54 }],
grouped = Array.from(
array.reduce((m, { key, val }) => m.set(key, (m.get(key) || 0) + val), new Map),
([key, val]) => ({ key, val })
);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var objArr = [
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:42},
{key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
{key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23},
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:54}]
var targetObj = {};
for (var i = 0; i < objArr.length; i++) {
if (!targetObj.hasOwnProperty(objArr[i].key)) {
targetObj[objArr[i].key] = 0;
}
targetObj[objArr[i].key] += objArr[i].val;
}
console.log(targetObj);
Array#reduce
与对象一起使用来存储每个键的值。
let arr = [{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:42},{key:'Mon Sep 24 2013 00:00:00 GMT-0400', val:78},{key:'Mon Sep 25 2013 00:00:00 GMT-0400', val:23},{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:54}];
let res = Object.values(arr.reduce((acc, curr)=>{
(acc[curr.key] = acc[curr.key] || {key: curr.key, val: 0}).val += curr.val;
return acc;
}, {}));
console.log(res);
在较新的浏览器中,可以使用逻辑空赋值。
let arr = [{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:42},{key:'Mon Sep 24 2013 00:00:00 GMT-0400', val:78},{key:'Mon Sep 25 2013 00:00:00 GMT-0400', val:23},{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:54}];
let res = Object.values(arr.reduce((acc, curr)=>{
(acc[curr.key] ??= {key: curr.key, val: 0}).val += curr.val;
return acc;
}, {}));
console.log(res);
试试这个。它应该有帮助。
var arr1 = [
{ name: 'besart', value: 12 },
{ name: 'astrit', value: 10 },
{ name: 'astrit', value: 10 },
{ name: 'besar', value: 18 },
{ name: 'besar', value: 3 },
{ name: 'astrit', value: 3 },
{ name: 'besart', value: 3 },
{ name: 'besart', value: 10 },
{ name: 'besar', value: 0 },
];
var arr2 = [];
var emri = "";
var value = 0;
for (var i = 0; i < arr1.length; i++) {
emri = arr1[0].name;
value += arr1[0].value;
for (var j = 1; j < arr1.length; j++) {
if (emri == arr1[j].name) {
value += arr1[j].value;
arr1.splice(j, 1);
j--;
}
}
arr1.splice(0, 1);
arr2[i] = {
name: emri,
value: value
};
value = 0;
}
console.log(arr2);
下面是另一个仅使用一个循环(while 循环)的解决方案:
var arr1 = [
{ name: 'besart', value: 12 },
{ name: 'astrit', value: 10 },
{ name: 'astrit', value: 10 },
{ name: 'besar', value: 18 },
{ name: 'besar', value: 3 },
{ name: 'astrit', value: 3 },
{ name: 'besart', value: 3 },
{ name: 'besart', value: 10 },
{ name: 'besar', value: 0 },
];
var arr2 = [];
var emri = "";
var value = 0;
var i = 1;
var j = 0;
while (arr1.length != 0) {
emri = arr1[0].name;
if (emri == arr1[i].name) {
value += arr1[i].value;
arr1.splice(i, 1);
i--;
}
i++;
if (i == arr1.length) {
value += arr1[0].value;
i = 1;
arr2[j] = {
name: emri,
value: value
};
j++;
value = 0;
arr1.splice(0, 1);
}
}
console.log(arr2)
你也可以尝试使用JavaScript linq框架,它与SQL语句完全相同,SQL语句以较少的代码给出所需的输出,并且有效,可以在linq.js中找到。
var objArr =
[
{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:42},
{key:'Mon Sep 24 2013 00:00:00 GMT-0400', val:78},
{key:'Mon Sep 25 2013 00:00:00 GMT-0400', val:23},
{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:54}
];
var aggregatedObject = Enumerable.From(objArr)
.GroupBy("$.key", null,
function (key, g) {
return {
key: key,
contributions: g.Sum("$.val")
}
})
.ToArray();
console.log(aggregatedObject);
<script src="http://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>
与循环相比,这很容易。
最近我需要一个类似的实现,我使用了某个使用reduce函数的人提供的类似解决方案。
几天后,我想自己实现类似的东西,这就是结果。
const users = [
{ id: 1, name: 'ernest', spent: 40 },
{ id: 2, name: 'ernest', spent: 40 },
{ id: 3, name: 'astrit', spent: 22 },
{ id: 4, name: 'astrit', spent: 2956 },
{ id: 5, name: 'astrit', spent: 22 },
{ id: 6, name: 'besart', spent: 40 },
{ id: 7, name: 'besart', spent: 100},
{ id: 8, name: 'besart', spent: 4000 }
];
const sum = [];
users.forEach(el => {
if(sum.length === 0) {
delete el.id;
sum.push(el);
}
else
{
const get = () => {
for(let i = 0; i < sum.length; i++) {
if(sum[i].name === el.name) {
return { stat: true, id: i };
}
}
}
let i = get();
if(i) {
sum[i.id].spent += el.spent;
}
else
{
delete el.id;
sum.push(el);
}
}
});
console.log(sum);
输出:
[ { name: 'ernest', spent: 80 }, { name: 'astrit', spent: 3000 }, { name: 'besart', spent: 4140 } ]
这是您的替代方案,但类似于爆炸药丸。它重用原始数组,而不是创建一个新的数组或不同的对象。这种排序可能不是必需的,并且会稍微减慢速度,但可以将其删除。
JavaScript
function reduceMyObjArr(arr) {
var temp = {},
index;
for (index = arr.length - 1; index >= 0; index -= 1) {
key = arr[index].key;
if (temp.hasOwnProperty(key)) {
arr[temp[key]].val += arr[index].val;
arr.splice(index, 1);
} else {
temp[key] = index;
}
}
arr.sort(function (a, b) {
if (a.key === b.key) {
return 0;
}
if (a.key < b.key) {
return -1;
}
return 1;
});
return arr;
}
var myObjArr = [{
key: "Mon Sep 23 2013 00: 00: 00 GMT - 0400",
val: 42
}, {
key: "Mon Sep 24 2013 00: 00: 00 GMT - 0400",
val: 78
}, {
key: "Mon Sep 25 2013 00: 00: 00 GMT - 0400",
val: 23
}, {
key: "Mon Sep 23 2013 00: 00: 00 GMT - 0400",
val: 54
}];
reduceMyObjArr(myObjArr);
console.log(myObjArr);
js小提琴
还有一个 jsperf,它将这个(有和没有排序)与公认的答案进行比较。您可以通过扩展数据集来改进性能测试。
function sumGroupBy(array, groupColumn, valueColumn) {
var res = []
array.forEach((item) => {
if(res.map((el) => el[groupColumn]).includes(item[groupColumn])) {
res.filter((el) => el[groupColumn] == item[groupColumn])[0][valueColumn] += item[valueColumn]
} else {
eval(`res.push({${groupColumn}: "${item[groupColumn]}", ${valueColumn}: ${item[valueColumn]} })`)
}
});
return res;
}
const pets = [
{type:"Dog", age:12},
{type:"Cat", age:13},
{type:"Dog", age:6},
{type:"Cat", age:18}
];
console.log(sumGroupBy(pets, 'type', 'age' ))
// [ { type: 'Dog', age: 18 }, { type: 'Cat', age: 31 } ]
下面是一个更通用的函数,可用于根据指定的键groupKey
对对象数组进行分组,并计算指定属性sumKey
的总和:
function groupAndSum(arr, groupKey, sumKey) {
return Object.values(
arr.reduce((acc, curr) => {
const group = curr[groupKey];
acc[group] = acc[group] || {
[groupKey]: group,
[sumKey]: 0
};
acc[group][sumKey] += curr[sumKey];
return acc;
}, {})
);
}
演示:
let objArr = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54 } ];
function groupAndSum(arr, groupKey, sumKey) {
return Object.values(
arr.reduce((acc, curr) => {
const group = curr[groupKey];
acc[group] = acc[group] || {
[groupKey]: group,
[sumKey]: 0
};
acc[group][sumKey] += curr[sumKey];
return acc;
}, {})
);
}
console.log(groupAndSum(objArr, 'key', 'val'))
function mergeDuplicatesBy(array, getKey, mergeWith) {
const buff = {}
array.forEach(function (arrayElement) {
const key = getKey(arrayElement)
const alreadyExistingVal = buff[key]
if (alreadyExistingVal) {
buff[key] = mergeWith(alreadyExistingVal, arrayElement)
} else {
buff[key] = arrayElement
}
})
return Object.values(buff)
}
mergeDuplicatesBy(
arr,
x => x.name,
(x, y) => ({ name: x.name, foo: x.foo + y.foo })
)
- 如何从对象的原型方法访问JavaScript对象属性
- 如何将数组项添加到对象属性中
- 设置嵌套对象属性的更好方法
- JavaScript管理具有重复属性名称的对象属性
- 如何使用element.myobj.prop等具有对象属性的元素
- 如何使用(this)访问Angular 2 http rxjs catch函数中的对象属性
- Es6:能够在设置/更新/删除对象属性时调用自定义方法
- 如何在AngularJS工厂中正确声明对象属性
- 如何使用object.assign()从其他对象引用基本对象属性
- 使用XPath样式访问Javascript JSON对象属性
- 将javascript对象(属性+值)合并到一个对象中
- 数组:使对象属性成为数组键
- 无法从JavaScript中的函数调用对象属性
- Google Closure Advanced |无法识别对象属性|动态属性
- Javascript从匿名函数访问外部对象属性
- 从函数更改对象属性
- 如何从字符串变量访问对象属性
- 从嵌套对象属性中获取排除某个值的最高值
- 在Aurelia computeds中,当设置依赖关系时,如何声明对对象属性的依赖关系
- 传递数量不确定的可能嵌套的对象属性