如何在可以有多个新生成的键的对象数组中对等效键的值求和?
How to sum values of equivalent keys in an array of objects where there can be multiple, newly generated keys?
存在一个像这样的对象数组,其中有一个 'category' 键和一些 'series' 键。
arrOne = [
{
"series_1": 25,
"category": "Category 1",
"series_2": 50
},
{
"series_1": 11,
"category": "Category 2",
"series_2": 22
},
{
"series_1": 32,
"category": "Category 1",
"series_2": 74
},
{
"series_1": 74,
"category": "Category 3",
"series_2": 98
},
{
"series_1": 46,
"category": "Category 3",
"series_2": 29
},
]
(请注意,'category' 几乎可以是任何值,尽管可能会有多个相似的值以及一些独特的值,例如,有多个具有 'category' 值的对象 'Category 3' 但只有 1 个具有 'category' 值 'Category 2')
下面的代码行将把具有相同类别
的对象的所有series_1相加
var objForAllCategories = {};
this.arrOne.forEach(item => {
if (objForAllCategories.hasOwnProperty(item.category))
objForAllCategories[item.category] = objForAllCategories[item.category] + item.series_1;
else
objForAllCategories[item.category] = item.series_1;
});
for (var prop in objForAllCategories) {
this.allCategoriesAndValues.push({
category: prop,
series_1: objForAllCategories[prop]
});
}
所以它会导致:
allCategoriesAndValues = [
{
"category": "Category 1",
"series_1": 57 // 25 + 32 adding up series_1 from all 'Category 1' items in arrOne
},
{
"category": "Category 2",
"series_1": 11 // only 1 'Category 2' from arrOne
},
{
"category": "Category 3",
"series_1": 120 // 74 + 46 adding up series_1 from all 'Category 3' items in arrOne
}
]
但是,我不仅希望能够添加 series_1,还希望能够添加所有其他项目。
这个例子只有类别和 series_1 和 series_2 作为键。但是,可能有:
- series_3
- series_4
- series_5
- series_6
- series_7
- 等..
我如何解释所有潜在的 series_x?
预期结果:
allCategoriesAndValues = [
{
"category": "Category 1",
"series_1": 57,
"series_2": 124,
..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
},
{
"category": "Category 2",
"series_1": 11,
"series_2": 22,
..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
},
{
"category": "Category 3",
"series_1": 120,
"series_2": 127,
..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
}
]
要处理多个属性逻辑,您可以遍历每个 属性 并检查它是否与正则表达式 series_\d+
匹配。如果是,您知道它是一个需要递增的 属性,并相应地处理它(属性 存在性检查也是必要的,正如 Jayce444 所指出的那样)。
以下解决方案使用Array.reduce
。在 reducer 函数中,它检查累加器数组是否包含与当前正在循环的项具有相同 category
属性 的项。如果是这样,它将增加适当的属性。否则,它会将当前项推送到累加器数组。
arrOne=[{series_1:25,category:"Category 1",series_2:50},{series_1:11,category:"Category 2",series_2:22},{series_1:32,category:"Category 1",series_2:74},{series_1:74,category:"Category 3",series_2:98},{series_1:46,category:"Category 3",series_2:29,series_3:50}];
const res = arrOne.reduce((a, b) => {
let found = a.find(e => e.category == b.category)
if (found) {
Object.keys(b).forEach(e => {
if (/series_\d+/g.test(e)) found[e] = found[e] ? found[e] + b[e] : b[e];
})
} else {
a.push(b)
}
return a;
}, [])
console.log(res)
创建地图以按类别整理系列总和。
然后从该映射创建一个数组,键为 category
const arr1 = [{"series_1":25,"category":"Category 1","series_2":50},{"series_1":11,"category":"Category 2","series_2":22},{"series_1":32,"category":"Category 1","series_2":74},{"series_1":74,"category":"Category 3","series_2":98},{"series_1":46,"category":"Category 3","series_2":29}]
const t1 = performance.now()
const cats = arr1.reduce((map, { category, ...series }) =>
map.set(category, Object.entries(series)
.reduce((s, [ key, count ]) => ({
...s,
[ key ]: (s[key] ?? 0) + count
}), map.get(category) ?? {})
), new Map())
const allCategoriesAndValues = Array.from(cats, ([ category, series ]) => ({
category,
...series
}))
const t2 = performance.now()
console.info(allCategoriesAndValues)
console.log(`Took ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }
类似这样的方法可行。
arrOne = [ { "series_1": 25, "category": "Category 1", "series_2": 50 }, { "series_1": 11, "category": "Category 2", "series_2": 22 }, { "series_1": 32, "category": "Category 1", "series_2": 74 }, { "series_1": 74, "category": "Category 3", "series_2": 98 }, { "series_1": 46, "category": "Category 3", "series_2": 29 },];
const result = [];
arrOne.reduce((acc, {category, ...series}) => {
if (acc.has(category)) {
Object.entries(series).forEach(([key, value]) => {
if (key.startsWith('series_')) {
acc.get(category)[key] = (acc.get(category)[key] || 0) + value;
}
});
} else {
const item = {category, ...series};
result.push(item);
acc.set(category, item);
}
return acc;
}, new Map());
console.log(result);
我会这样做...
const arrOne =
[ { series_1: 25, category: 'Category 1', series_2: 50 }
, { series_1: 11, category: 'Category 2', series_2: 22 }
, { series_1: 32, category: 'Category 1', series_2: 74 }
, { series_1: 74, category: 'Category 3', series_2: 98 }
, { series_1: 46, category: 'Category 3', series_2: 29 }
]
console.time('chrono')
const allCategoriesAndValues =
Object.entries(
arrOne.reduce((r,{ category, ...series })=>
{
let cat = r[category] = r[category] ?? {}
Object.entries(series).forEach(([sName,val]) => cat[sName] = (cat[sName] ?? 0) + val);
return r
},{})
).map(([category,series])=>({category,...series}))
console.timeEnd('chrono')
console.log( allCategoriesAndValues )
.as-console-wrapper {max-height: 100%!important;top:0 }
您可以只遍历对象数组,然后遍历每个对象的键,存储到缓冲区对象中。您只需要检查每个键是否存在并在缺少时添加它,或者您可以像我一样将错误的键合并为默认值。我在获取对象的值后从对象中删除类别键,这样我就不必在键迭代期间尝试跳过它。
const arrOne = [
{"series_1": 25, "category": "Category 1", "series_2": 50},
{"series_1": 11, "category": "Category 2", "series_2": 22},
{"series_1": 32, "category": "Category 1", "series_2": 74},
{"series_1": 74, "category": "Category 3", "series_2": 98},
{"series_1": 46, "category": "Category 3", "series_2": 29},
];
let buffer = {};
arrOne.forEach(i=>{
let c = i.category;
buffer[c] = buffer[c] || {};
delete i.category;
Object.keys(i).forEach(k=>{
buffer[c][k] = buffer[c][k] || 0;
buffer[c][k] += i[k];
});
});
console.log(buffer);
let final = Object.keys(buffer).map(k=>{return {[k]: buffer[k]}});
console.log(final);
如果您不需要在数组中包含它,则最后一步是可选的。它的存在只是为了将对象转化为数组。
这是我的做法
const res = arrOne.reduce((acc, { category, ...vals }) => {
if (acc[category]) {
Object.entries(vals).forEach(([ key, val ]) => acc[category][key] = acc[category][key] ? acc[category][key] + val : val);
} else {
acc[category] = vals;
}
return acc;
}, {});
存在一个像这样的对象数组,其中有一个 'category' 键和一些 'series' 键。
arrOne = [
{
"series_1": 25,
"category": "Category 1",
"series_2": 50
},
{
"series_1": 11,
"category": "Category 2",
"series_2": 22
},
{
"series_1": 32,
"category": "Category 1",
"series_2": 74
},
{
"series_1": 74,
"category": "Category 3",
"series_2": 98
},
{
"series_1": 46,
"category": "Category 3",
"series_2": 29
},
]
(请注意,'category' 几乎可以是任何值,尽管可能会有多个相似的值以及一些独特的值,例如,有多个具有 'category' 值的对象 'Category 3' 但只有 1 个具有 'category' 值 'Category 2')
下面的代码行将把具有相同类别
的对象的所有series_1相加 var objForAllCategories = {};
this.arrOne.forEach(item => {
if (objForAllCategories.hasOwnProperty(item.category))
objForAllCategories[item.category] = objForAllCategories[item.category] + item.series_1;
else
objForAllCategories[item.category] = item.series_1;
});
for (var prop in objForAllCategories) {
this.allCategoriesAndValues.push({
category: prop,
series_1: objForAllCategories[prop]
});
}
所以它会导致:
allCategoriesAndValues = [
{
"category": "Category 1",
"series_1": 57 // 25 + 32 adding up series_1 from all 'Category 1' items in arrOne
},
{
"category": "Category 2",
"series_1": 11 // only 1 'Category 2' from arrOne
},
{
"category": "Category 3",
"series_1": 120 // 74 + 46 adding up series_1 from all 'Category 3' items in arrOne
}
]
但是,我不仅希望能够添加 series_1,还希望能够添加所有其他项目。
这个例子只有类别和 series_1 和 series_2 作为键。但是,可能有:
- series_3
- series_4
- series_5
- series_6
- series_7
- 等..
我如何解释所有潜在的 series_x?
预期结果:
allCategoriesAndValues = [
{
"category": "Category 1",
"series_1": 57,
"series_2": 124,
..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
},
{
"category": "Category 2",
"series_1": 11,
"series_2": 22,
..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
},
{
"category": "Category 3",
"series_1": 120,
"series_2": 127,
..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
}
]
要处理多个属性逻辑,您可以遍历每个 属性 并检查它是否与正则表达式 series_\d+
匹配。如果是,您知道它是一个需要递增的 属性,并相应地处理它(属性 存在性检查也是必要的,正如 Jayce444 所指出的那样)。
以下解决方案使用Array.reduce
。在 reducer 函数中,它检查累加器数组是否包含与当前正在循环的项具有相同 category
属性 的项。如果是这样,它将增加适当的属性。否则,它会将当前项推送到累加器数组。
arrOne=[{series_1:25,category:"Category 1",series_2:50},{series_1:11,category:"Category 2",series_2:22},{series_1:32,category:"Category 1",series_2:74},{series_1:74,category:"Category 3",series_2:98},{series_1:46,category:"Category 3",series_2:29,series_3:50}];
const res = arrOne.reduce((a, b) => {
let found = a.find(e => e.category == b.category)
if (found) {
Object.keys(b).forEach(e => {
if (/series_\d+/g.test(e)) found[e] = found[e] ? found[e] + b[e] : b[e];
})
} else {
a.push(b)
}
return a;
}, [])
console.log(res)
创建地图以按类别整理系列总和。
然后从该映射创建一个数组,键为 category
const arr1 = [{"series_1":25,"category":"Category 1","series_2":50},{"series_1":11,"category":"Category 2","series_2":22},{"series_1":32,"category":"Category 1","series_2":74},{"series_1":74,"category":"Category 3","series_2":98},{"series_1":46,"category":"Category 3","series_2":29}]
const t1 = performance.now()
const cats = arr1.reduce((map, { category, ...series }) =>
map.set(category, Object.entries(series)
.reduce((s, [ key, count ]) => ({
...s,
[ key ]: (s[key] ?? 0) + count
}), map.get(category) ?? {})
), new Map())
const allCategoriesAndValues = Array.from(cats, ([ category, series ]) => ({
category,
...series
}))
const t2 = performance.now()
console.info(allCategoriesAndValues)
console.log(`Took ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }
类似这样的方法可行。
arrOne = [ { "series_1": 25, "category": "Category 1", "series_2": 50 }, { "series_1": 11, "category": "Category 2", "series_2": 22 }, { "series_1": 32, "category": "Category 1", "series_2": 74 }, { "series_1": 74, "category": "Category 3", "series_2": 98 }, { "series_1": 46, "category": "Category 3", "series_2": 29 },];
const result = [];
arrOne.reduce((acc, {category, ...series}) => {
if (acc.has(category)) {
Object.entries(series).forEach(([key, value]) => {
if (key.startsWith('series_')) {
acc.get(category)[key] = (acc.get(category)[key] || 0) + value;
}
});
} else {
const item = {category, ...series};
result.push(item);
acc.set(category, item);
}
return acc;
}, new Map());
console.log(result);
我会这样做...
const arrOne =
[ { series_1: 25, category: 'Category 1', series_2: 50 }
, { series_1: 11, category: 'Category 2', series_2: 22 }
, { series_1: 32, category: 'Category 1', series_2: 74 }
, { series_1: 74, category: 'Category 3', series_2: 98 }
, { series_1: 46, category: 'Category 3', series_2: 29 }
]
console.time('chrono')
const allCategoriesAndValues =
Object.entries(
arrOne.reduce((r,{ category, ...series })=>
{
let cat = r[category] = r[category] ?? {}
Object.entries(series).forEach(([sName,val]) => cat[sName] = (cat[sName] ?? 0) + val);
return r
},{})
).map(([category,series])=>({category,...series}))
console.timeEnd('chrono')
console.log( allCategoriesAndValues )
.as-console-wrapper {max-height: 100%!important;top:0 }
您可以只遍历对象数组,然后遍历每个对象的键,存储到缓冲区对象中。您只需要检查每个键是否存在并在缺少时添加它,或者您可以像我一样将错误的键合并为默认值。我在获取对象的值后从对象中删除类别键,这样我就不必在键迭代期间尝试跳过它。
const arrOne = [
{"series_1": 25, "category": "Category 1", "series_2": 50},
{"series_1": 11, "category": "Category 2", "series_2": 22},
{"series_1": 32, "category": "Category 1", "series_2": 74},
{"series_1": 74, "category": "Category 3", "series_2": 98},
{"series_1": 46, "category": "Category 3", "series_2": 29},
];
let buffer = {};
arrOne.forEach(i=>{
let c = i.category;
buffer[c] = buffer[c] || {};
delete i.category;
Object.keys(i).forEach(k=>{
buffer[c][k] = buffer[c][k] || 0;
buffer[c][k] += i[k];
});
});
console.log(buffer);
let final = Object.keys(buffer).map(k=>{return {[k]: buffer[k]}});
console.log(final);
如果您不需要在数组中包含它,则最后一步是可选的。它的存在只是为了将对象转化为数组。
这是我的做法
const res = arrOne.reduce((acc, { category, ...vals }) => {
if (acc[category]) {
Object.entries(vals).forEach(([ key, val ]) => acc[category][key] = acc[category][key] ? acc[category][key] + val : val);
} else {
acc[category] = vals;
}
return acc;
}, {});