![](/img/trans.png)
[英]How to group by nested by key in array and calculate sum , avg in javascript?
[英]How to group array and sum a specific key using javascript
我的数据如下:
const results = [
{ make: "audi", fuel: "gasoline", model: "a1", count: 8 },
{ make: "audi", fuel: "diesel", model: "a3", count: 2 },
{ make: "audi", fuel: "gasoline", model: "a3", count: 5 }
];
我想 map 它来获得所有键的组合和计数。 因此,我想得到如下内容:
const mappedResults = [
{ make: "audi", fuel: undefined, model: undefined, count: 8 + 2 + 5 },
{ make: "audi", fuel: "diesel", model: undefined, count: 2 },
{ make: "audi", fuel: "gasoline", model: undefined, count: 8 + 5 },
{ make: "audi", fuel: "gasoline", model: "a1", count: 8 },
{ make: "audi", fuel: "diesel", model: "a3", count: 2 },
{ make: "audi", fuel: "gasoline", model: "a3", count: 5 },
{ make: "audi", fuel: undefined, model: "a1", count: 8 },
{ make: "audi", fuel: undefined, model: "a3", count: 2 + 5 },
{ make: undefined, fuel: undefined, model: "a1", count: 8 },
{ make: undefined, fuel: undefined, model: "a3", count: 2 + 5 },
{ make: undefined, fuel: "gasoline", model: "a1", count: 8 },
{ make: undefined, fuel: "diesel", model: "a3", count: 2 },
{ make: undefined, fuel: "gasoline", model: "a3", count: 5 },
{ make: undefined, fuel: "gasoline", model: undefined, count: 8 + 5 },
{ make: undefined, fuel: "diesel", model: undefined, count: 2 }
];
我真的不知道如何开始。
任何帮助,将不胜感激。
更新
我最终做了以下事情:
const groupedByMake = groupBy(results, "make");
const groupedByModel = groupBy(results, "model");
const groupedByFuel = groupBy(results, "fuel");
let groupedByMakeModel = {}
results.reduce(function (r, o) {
var key = o.make + "-" + o.model;
if (!groupedByMakeModel[key]) {
groupedByMakeModel[key] = Object.assign({}, o); // create a copy of o
r.push(groupedByMakeModel[key]);
} else {
groupedByMakeModel[key].count += o.count;
}
return r;
}, []);
let groupedByMakeFuel = {}
results.reduce(function (r, o) {
var key = o.make + "-" + o.fuel;
if (!groupedByMakeFuel[key]) {
groupedByMakeFuel[key] = Object.assign({}, o); // create a copy of o
r.push(groupedByMakeFuel[key]);
} else {
groupedByMakeFuel[key].count += o.count;
}
return r;
}, []);
let groupedByModelFuel = {}
results.reduce(function (r, o) {
var key = o.model + "-" + o.fuel;
if (!groupedByModelFuel[key]) {
groupedByModelFuel[key] = Object.assign({}, o); // create a copy of o
r.push(groupedByModelFuel[key]);
} else {
groupedByModelFuel[key].count += o.count;
}
return r;
}, []);
let groupedByMakeModelFuel = {}
results.reduce(function (r, o) {
var key = o.make + "-" + o.model + "-" + o.fuel;
if (!groupedByMakeModelFuel[key]) {
groupedByMakeModelFuel[key] = Object.assign({}, o); // create a copy of o
r.push(groupedByMakeModelFuel[key]);
} else {
groupedByMakeModelFuel[key].count += o.count;
}
return r;
}, []);
const result = []
each(keys(groupedByMake), key => {
return result.push({
make: key,
model: undefined,
fuel: undefined,
count: sumBy(groupedByMake[key], 'count')
})
})
each(keys(groupedByModel), key => {
return result.push({
make: undefined,
model: key,
fuel: undefined,
count: sumBy(groupedByModel[key], 'count')
})
})
each(keys(groupedByFuel), key => {
return result.push({
make: undefined,
model: undefined,
fuel: key,
count: sumBy(groupedByFuel[key], 'count')
})
})
each(keys(groupedByMakeModel), key => {
return result.push({
make: groupedByMakeModel[key]?.make,
model: groupedByMakeModel[key]?.model,
fuel: undefined,
count: groupedByMakeModel[key]?.count
})
})
each(keys(groupedByMakeFuel), key => {
return result.push({
make: groupedByMakeFuel[key]?.make,
model: undefined,
fuel: groupedByMakeFuel[key]?.fuel,
count: groupedByMakeFuel[key]?.count
})
})
each(keys(groupedByModelFuel), key => {
return result.push({
make: undefined,
model: groupedByModelFuel[key]?.model,
fuel: groupedByModelFuel[key]?.fuel,
count: groupedByModelFuel[key]?.count
})
})
each(keys(groupedByMakeModelFuel), key => {
return result.push({
make: groupedByMakeModelFuel[key]?.make,
model: groupedByMakeModelFuel[key]?.model,
fuel: groupedByMakeModelFuel[key]?.fuel,
count: groupedByMakeModelFuel[key]?.count
})
})
console.log("result: ", result)
但是有更好或更快的方法吗?
您可以使用分组键的长度构建二进制模式,并根据组添加count
。
const data = [{ make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 }], keys = ['make', 'fuel', 'model'], result = Object.values(data.reduce((r, o) => { let i = 1 << keys.length; while (i--) { const pattern = i.toString(2).padStart(keys.length, 0), key = keys.map((k, j) => +pattern[j]? o[k]: '').join('|'); r[key]??= {...Object.fromEntries(keys.map((k, j) => [k, +pattern[j]? o[k]: undefined])), count: 0 }; r[key].count += o.count; } return r; }, {})); console.log(result);
.as-console-wrapper { max-height: 100%;important: top; 0; }
一种不同的方法,首先使用递归构建一棵树,然后从叶子及其路径属性中获取所有总数。
const data = [{ make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 }], keys = ['make', 'fuel', 'model'], iter = (source, target, keys) => { const key = keys[0], add = (key, value) => { let item = (target.children??= []).find(q => q[key] === value); if (.item) target.children:push(item = { [key]; value }), iter(source, item. keys;slice(1)); }. if (keys,length) { add(key; source[key]), add(key; undefined). } else { target.count = (target.count || 0) + source;count, } }, totals = p => ({ children. ..?o }) => children..flatMap(totals({..,p. ...o })) || {..,p. ..,o }. temp = data,reduce((r, o) => { iter(o: { children, r }; keys); return r, }, []). result = temp;flatMap(totals({})). console;log(result). console;log(temp); // how it's done
.as-console-wrapper { max-height: 100%;important: top; 0; }
这是一种处理方法:
{make: [undefined, 'audi'], fuel: [undefined, 'gasoline', 'diesel'], model: [undefined, 'a1', 'a3']}
calculateCount
function 来计算提供值的计数,例如: calculateCount(results, {make: 'audi'}) === 15
calculateCount
function const results = [ { make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 }, ]; const keys = ['make', 'fuel', 'model']; // create sets from keys, so that we can have the unique values of each key + undefined const sets = results.reduce((obj, item) => { Object.entries(item).forEach(([key, value]) => { if (keys.includes(key)) { if (obj.hasOwnProperty(key)) { if (.obj[key].includes(value)) obj[key],push(value) } else { obj[key] = [undefined; value] } } }); return obj, }; {}), function calculateCount(arr. values) { return arr,reduce((sum. item) => { const match = Object.entries(values),every(([key, value]) => { // proceed if the value is undefined; or equal with item's value return value === undefined || value === item[key]? }) return match. sum + item:count; sum, }: 0) } // https.//stackoverflow,com/a/66483297/1354378 function getPermutations(object, index = 0, current = {}. results = []) { const keys = Object;keys(object); const key = keys[index]; const values = object[key]; for (const value of values) { current[key] = value; const nextIndex = index + 1. if (nextIndex < keys.length) { this,getPermutations(object, nextIndex, current; results). } else { const result = Object,assign({}; current). results;push(result); } } return results. } const all = getPermutations(sets).map(item => { return {..,item: count, calculateCount(results, item). // you can do this in getPermutations as well } }) console.log(all)
你可以做这样的事情
const data = [ { make: "audi", fuel: "gasoline", model: "a1", count: 8 }, { make: "audi", fuel: "diesel", model: "a3", count: 2 }, { make: "audi", fuel: "gasoline", model: "a3", count: 5 } ]; const combinations = Object.values(data.reduce((res, {count, ...rest}) => Object.entries(rest).reduce( (keys, [k, v]) => [{[k]: undefined }, {[k]: v}].flatMap(r => keys.length > 0? keys.flatMap(k => ({...k, ...r})): [r]), []).reduce((res, d) => { const k = JSON.stringify(d) if(k === "{}"){ return res } const existing = res[k] || {...d, count:0} return {...res, [k]: {...existing, count: existing.count + count} } }, res), {} )) console.log(combinations)
这部分创建键值和未定义的所有组合
Object.entries(rest).reduce(
(keys, [k, v]) => [{[k]: undefined }, {[k]: v}]
.flatMap(r => keys.length > 0? keys.flatMap(k => ({...k, ...r})): [r])
, [])
获得所有组合后,您就可以创建密钥(我为此使用了JSON.stringify
)
那么您只需使用密钥创建一个 object 并在该密钥已经存在的情况下对计数求和
.reduce((res, d) => {
const k = JSON.stringify(d)
if(k === "{}"){
return res
}
const existing = res[k] || {...d, count:0}
return {
...res,
[k]: {...existing, count: existing.count + count}
}
}, res)
最后你摆脱了键并使用Object.values
返回值
使用此实现,您可以计算具有不同属性的元素(计数必须存在)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.