[英]Group object array by multiple fields and add the values for a key
我知道這個問題已經被問過很多次了,但是,不幸的是,我沒有找到任何對我的案子有幫助的答案。
這是我的數據的樣子:
let data= [
{
"estimated_cost": 1.14,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.19,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.08,
"inventory_type": "fuel",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.17,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.03,
"inventory_type": "fuel",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.20,
"inventory_type": "power",
"cost_center_name": "Mac",
},
{
"estimated_cost": 1.19,
"inventory_type": "water",
"cost_center_name": "Mac",
},
{
"estimated_cost": 1.14,
"inventory_type": "power",
"cost_center_name": "Mac",
},
{
"estimated_cost": 1.18,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
}
];
我想按兩個字段進行分組,即inventory_type
和cost_center_name
,並添加estimated_cost
的值。
我的 output 應該是這樣的:
[
{
"estimated_cost": 4.68,
"inventory_type": "power",
"cost_center_name": "Ex Hall"
},
{
"estimated_cost": 2.11,
"inventory_type": "fuel",
"cost_center_name": "Ex Hall"
},
{
"estimated_cost": 2.34,
"inventory_type": "power",
"cost_center_name": "Mac"
},
{
"estimated_cost": 1.19,
"inventory_type": "water",
"cost_center_name": "Mac"
},
]
我有這個代碼按單個字段分組並添加值,以防這有幫助:
export const groupBy = (data, groupByVar) => {
var array = [];
data.reduce(function (res, value) {
if (!res[value[groupByVar]]) {
let row = {};
row[groupByVar] = value[groupByVar];
row["estimated_cost"] = 0;
row["cost_center_name"] = value["cost_center_name"];
row["inventory_type"] = value["inventory_type"];
res[value[groupByVar]] = row;
array.push(res[value[groupByVar]]);
}
res[value[groupByVar]].estimated_cost += value.estimated_cost;
return res;
}, {});
return array;
};
這是一個通用解決方案,它應該與您想要分組的任意鍵一起使用。
主要的 function 是groupByFields
,它采用對象數組和字段列表,並生成按字段分組的扁平對象數組。 flattenObj
是一個幫助器 function 來清理groupByFields
用於內部簿記的分組對象。
之后,就是對每組中的元素進行求和。 如果將函數視為庫,則客戶端邏輯相當干凈。
概括減少 function 似乎為時過早,但如果您經常這樣做,您可以將estimated_cost
作為參數並將整個內容打包到另一個 function 中。
const data = [ { "estimated_cost": 1.14, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.19, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.08, "inventory_type": "fuel", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.17, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.03, "inventory_type": "fuel", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.20, "inventory_type": "power", "cost_center_name": "Mac", }, { "estimated_cost": 1.19, "inventory_type": "water", "cost_center_name": "Mac", }, { "estimated_cost": 1.14, "inventory_type": "power", "cost_center_name": "Mac", }, { "estimated_cost": 1.18, "inventory_type": "power", "cost_center_name": "Ex Hall", } ]; const flattenObj = obj => { const arrays = []; for (const stack = [obj]; stack.length;) { const curr = stack.pop(); if (Array.isArray(curr)) { arrays.push(curr); } else { stack.push(...Object.values(curr)); } } return arrays.reverse(); }; const groupByFields = (a, fields) => flattenObj(a.reduce((a, e) => { let curr = a; fields.forEach((field, i) => { if (.curr[e[field]]) { curr[e[field]] = i === fields?length - 1: []; {}; } curr = curr[e[field]]; }). curr;push(e); return a, }; {})). const reducer = group => group,reduce((a. e) => ({..,e: estimated_cost. a.estimated_cost + e,estimated_cost }): {estimated_cost; 0}), const fields = ["cost_center_name"; "inventory_type"], const grouped = groupByFields(data; fields). console.log(grouped;map(reducer));
如果這對您來說過於籠統並且感覺代碼太多,您可以刪除整個flattenObj
function 並使用硬編碼
Object.values(grouped).map(o => Object.values(o).map(reducer))
反而。 這有效地將減少的 object 扁平化了兩個級別(您擁有的字段數),而不是像flattenObj
那樣的任意數量的級別。
遍歷數組並構建一個 object, all
具有作為庫存和成本中心名稱和值的組合的key
,以匯總估計成本。
const group = (arr) => { const all = {}; // Update key format as required. const getKey = ({ inventory_type, cost_center_name }) => `${inventory_type}||${cost_center_name}`; arr.forEach((item) => { const key = getKey(item); if (key in all) { all[key].estimated_cost += item.estimated_cost; } else { all[key] = {...item }; } }); return Object.values(all); }; let data = [ { estimated_cost: 1.14, inventory_type: "power", cost_center_name: "Ex Hall", }, { estimated_cost: 1.19, inventory_type: "power", cost_center_name: "Ex Hall", }, { estimated_cost: 1.08, inventory_type: "fuel", cost_center_name: "Ex Hall", }, { estimated_cost: 1.17, inventory_type: "power", cost_center_name: "Ex Hall", }, { estimated_cost: 1.03, inventory_type: "fuel", cost_center_name: "Ex Hall", }, { estimated_cost: 1.2, inventory_type: "power", cost_center_name: "Mac", }, { estimated_cost: 1.19, inventory_type: "water", cost_center_name: "Mac", }, { estimated_cost: 1.14, inventory_type: "power", cost_center_name: "Mac", }, { estimated_cost: 1.18, inventory_type: "power", cost_center_name: "Ex Hall", }, ]; console.log(group(data));
您可以基於多個鍵進行分組並加入它們,然后在累加器中添加estimated_cost
。
const data = [ { "estimated_cost": 1.14, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.19, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.08, "inventory_type": "fuel", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.17, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.03, "inventory_type": "fuel", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.20, "inventory_type": "power", "cost_center_name": "Mac", }, { "estimated_cost": 1.19, "inventory_type": "water", "cost_center_name": "Mac", }, { "estimated_cost": 1.14, "inventory_type": "power", "cost_center_name": "Mac", }, { "estimated_cost": 1.18, "inventory_type": "power", "cost_center_name": "Ex Hall", } ], result = Object.values(data.reduce((r, o) => { const key = o.inventory_type + '-' + o.cost_center_name; r[key] = r[key] || {...o, estimated_cost: 0}; r[key].estimated_cost += o.estimated_cost; return r; },{})); console.log(result);
我將使用您的 cost_center_name 和 inventory_type 對所有數據進行分組:
const groupAddition = (data) => {
let ret = {};
for (const each of data) {
const key = each.cost_center_name+each.inventory_type;
if (ret[key]) {
ret[key].estimated_cost += each.estimated_cost;
} else {
ret[key] = each;
}
}
return Object.values(ret).map((e) => {
e.estimated_cost = Math.round(e.estimated_cost * 100) / 100;
return e;
});
}
我添加了額外的步驟來四舍五入最終的估計成本,因為 JS 有時會返回 '2.1100000000000003' 以進行添加..
通過打印結果,它顯示
console.log(JSON.stringify(groupAddition(data), null, 2));
[
{
"estimated_cost": 4.68,
"inventory_type": "power",
"cost_center_name": "Ex Hall"
},
{
"estimated_cost": 2.11,
"inventory_type": "fuel",
"cost_center_name": "Ex Hall"
},
{
"estimated_cost": 2.34,
"inventory_type": "power",
"cost_center_name": "Mac"
},
{
"estimated_cost": 1.19,
"inventory_type": "water",
"cost_center_name": "Mac"
}
]
以下將適用於fields
數組中提到的任何鍵。 此代碼將按fields
數組中提到的所有字段進行分組。
你可以使用 reduce 來做到這一點,
const data = [ { "estimated_cost": 1.14, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.19, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.08, "inventory_type": "fuel", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.17, "inventory_type": "power", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.03, "inventory_type": "fuel", "cost_center_name": "Ex Hall", }, { "estimated_cost": 1.20, "inventory_type": "power", "cost_center_name": "Mac", }, { "estimated_cost": 1.19, "inventory_type": "water", "cost_center_name": "Mac", }, { "estimated_cost": 1.14, "inventory_type": "power", "cost_center_name": "Mac", }, { "estimated_cost": 1.18, "inventory_type": "power", "cost_center_name": "Ex Hall", } ]; const fields = ["cost_center_name", "inventory_type"]; const groupByFields = (obj, fields) => { return obj.reduce((prev, curr) => { index = prev.findIndex(item => { let found = true; fields.forEach(key => { found = found && item[key] === curr[key]; }); return found; }); if(index > -1) { prev[index].estimated_cost += curr.estimated_cost; } else { prev.push(curr); } return prev; }, []); } const res = groupByFields(data, fields); console.log(res);
要對條目進行分組,您可以遍歷數組並僅從必填字段創建 json 字符串。 這將創建一個唯一鍵,可用於 object 屬性條目,並允許我們檢測何時將條目組合在一起。
我們將把條目初始化為一個包含在列表中的 object ( intermediate[key] = [a]
),或者如果它已經存在則推送到數組。 然后我們可以去掉 object 鍵,只留下值,即我們的組。
第二階段是對estimated_costs
字段求和。 為此,我創建了一個特定的 function,而不是試圖將它全部塞進一個襯里。 function 獲取分組對象數組並從每個數組的第一個元素(它不能為空或不會從groupBy
返回)填充其他字段( inventory_type
, cost_center
),然后對estimated_costs
字段求和。
function makeKey(obj, props) {
const result = {};
for (p of props) {
result[p] = obj[p];
}
return JSON.stringify(result);
}
function groupBy(arr, fields) {
const intermediate = {};
for (let a of arr) {
const key = makeKey(a, fields);
const val = intermediate[key];
if (val !== undefined) val.push(a);
else intermediate[key] = [a];
}
return Object.values(intermediate);
}
let data = [
{
"estimated_cost": 1.14,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.19,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.08,
"inventory_type": "fuel",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.17,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.03,
"inventory_type": "fuel",
"cost_center_name": "Ex Hall",
},
{
"estimated_cost": 1.20,
"inventory_type": "power",
"cost_center_name": "Mac",
},
{
"estimated_cost": 1.19,
"inventory_type": "water",
"cost_center_name": "Mac",
},
{
"estimated_cost": 1.14,
"inventory_type": "power",
"cost_center_name": "Mac",
},
{
"estimated_cost": 1.18,
"inventory_type": "power",
"cost_center_name": "Ex Hall",
}
];
function sumCosts(group) {
return {
inventory_type: group[0].inventory_type,
cost_center_name: group[0].cost_center_name,
estimated_cost: group.map(g=>g.estimated_cost).reduce((accum, n) => accum + n, 0)
}
}
console.log(groupBy(data, ['inventory_type', 'cost_center_name']).map(sumCosts));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.