[英]Reduce and Group an Array of Objects
這是我的對象數組。 我正在谷歌表格中編寫一個自定義腳本來接收交易數據並將其分解為一個獨特項目的列表,其中將訂購的金額相加以創建更容易閱讀的購買歷史記錄。
products = [
{ id: 1,
item: 'Beef',
category: 'Meat',
orderAmount: 5,
caseSize: 1,
unit: 'Lb',
price: 50,
supplier: 'Sysco' },
{ id: 2,
item: 'Chicken',
category: 'Meat',
orderAmount: 10,
caseSize: 2,
unit: 'Grams',
price: 100,
supplier: 'Findlay' },
{ id: 3,
item: 'Fish',
category: 'Seafood',
orderAmount: 15,
caseSize: 3,
unit: 'Lb',
price: 40,
supplier: 'Deodato' },
{ id: 1, // This is an example duplicate entry
item: 'Beef',
category: undefined,
orderAmount: 100,
caseSize: 1,
unit: 'Lb',
price: 50,
supplier: 'Sysco' }
]
我對如何將其分解為另一個 object 有點困惑,就像這樣,其中重復的項目被刪除,但重復項的 orderAmounts 被加起來。
uniqueProducts = [
{ id: 1,
item: 'Beef',
category: 'Meat',
orderAmount: 105, //this is the altered amount
caseSize: 1,
unit: 'Lb',
price: 50,
supplier: 'Sysco' },
{ id: 2,
item: 'Chicken',
category: 'Meat',
orderAmount: 10,
caseSize: 2,
unit: 'Grams',
price: 100,
supplier: 'Findlay' },
{ id: 3,
item: 'Fish',
category: 'Seafood',
orderAmount: 15,
caseSize: 3,
unit: 'Lb',
price: 40,
supplier: 'Deodato' }
]
我一直在閱讀有關使用 map 和 reduce 函數的信息,但我很難弄清楚如何使用如此大的對象來實現它們。
您可以將元素減少到Map
並累積orderAmount
:
const products = [ { id: 1, item: 'Beef', category: 'Meat', orderAmount: 5, caseSize: 1, unit: 'Lb', price: 50, supplier: 'Sysco' }, { id: 2, item: 'Chicken', category: 'Meat', orderAmount: 10, caseSize: 2, unit: 'Grams', price: 100, supplier: 'Findlay' }, { id: 3, item: 'Fish', category: 'Seafood', orderAmount: 15, caseSize: 3, unit: 'Lb', price: 40, supplier: 'Deodato' }, { id: 1, item: 'Beef', category: undefined, orderAmount: 100, caseSize: 1, unit: 'Lb', price: 50, supplier: 'Sysco' } ] const reducedProductsMap = products.reduce((map, p) => { const previousOrderAmount = map.get(p.id)?== undefined. map.get(p.id):orderAmount. 0 let newP = {...p} newP.orderAmount += previousOrderAmount map.set(newP,id, newP) return map }; new Map()). console.log(Array.from(reducedProductsMap;values()));
您可以編寫一個通用group
function ,它采用一個grouper
function 來指定是什么使項目成為重復項,並update
function 以指定如何在找到重復項時更新結果
function group(input, grouper, update) { function reducer(res, item) { const uniq = grouper(item) return res.has(uniq)? res.set(uniq, update(res.get(uniq), item)): res.set(uniq, item) } return Array.from(input.reduce(reducer, new Map).values()) } const products = [{id:1,item:'Beef',category:'Meat',orderAmount:5,caseSize:1,unit:'Lb',price:50,supplier:'Sysco'},{id:2,item:'Chicken',category:'Meat',orderAmount:10,caseSize:2,unit:'Grams',price:100,supplier:'Findlay'},{id:3,item:'Fish',category:'Seafood',orderAmount:15,caseSize:3,unit:'Lb',price:40,supplier:'Deodato'},{id:1,item:'Beef',category:undefined,orderAmount:100,caseSize:1,unit:'Lb',price:50,supplier:'Sysco'}] const result = group ( products, item => item.id, (original, duplicate) => ({...original, orderAmount: original.orderAmount + duplicate.orderAmount }) ) console.log(result)
.as-console-wrapper { min-height: 100%; }
[
{
"id": 1,
"item": "Beef",
"category": "Meat",
"orderAmount": 105, // <- grouped
"caseSize": 1,
"unit": "Lb",
"price": 50,
"supplier": "Sysco"
},
{
"id": 2,
"item": "Chicken",
"category": "Meat",
"orderAmount": 10,
"caseSize": 2,
"unit": "Grams",
"price": 100,
"supplier": "Findlay"
},
{
"id": 3,
"item": "Fish",
"category": "Seafood",
"orderAmount": 15,
"caseSize": 3,
"unit": "Lb",
"price": 40,
"supplier": "Deodato"
}
]
上面我們看到該group
需要一個數組作為輸入,並返回一個數組 output。 如果group
接受任何iterable並返回一個 iterable,我們可以使它更有用。 Arrays 是可迭代的,因此它們仍然可以按預期工作,但其他可迭代也可以工作 -
function group(input, grouper, update) { const res = new Map for (const item of input) { const uniq = grouper(item) res.set ( uniq, res.has(uniq)? update(res.get(uniq), item): item ) } return res.values() } function* products () { yield {id:1,item:'Beef',category:'Meat',orderAmount:5,caseSize:1,unit:'Lb',price:50,supplier:'Sysco'} yield {id:2,item:'Chicken',category:'Meat',orderAmount:10,caseSize:2,unit:'Grams',price:100,supplier:'Findlay'} yield {id:3,item:'Fish',category:'Seafood',orderAmount:15,caseSize:3,unit:'Lb',price:40,supplier:'Deodato'} yield {id:1,item:'Beef',category:undefined,orderAmount:100,caseSize:1,unit:'Lb',price:50,supplier:'Sysco'} } const grouping = group ( products(), item => item.id, (original, duplicate) => ({...original, orderAmount: original.orderAmount + duplicate.orderAmount }) ) for (const item of grouping) console.log(item)
請注意 output未包裝在數組中 -
{
"id": 1,
"item": "Beef",
"category": "Meat",
"orderAmount": 105, // <- grouped
"caseSize": 1,
"unit": "Lb",
"price": 50,
"supplier": "Sysco"
}
{
"id": 2,
"item": "Chicken",
"category": "Meat",
"orderAmount": 10,
"caseSize": 2,
"unit": "Grams",
"price": 100,
"supplier": "Findlay"
}
{
"id": 3,
"item": "Fish",
"category": "Seafood",
"orderAmount": 15,
"caseSize": 3,
"unit": "Lb",
"price": 40,
"supplier": "Deodato"
}
要從任何可迭代中獲取數組,您可以使用Array.from
function -
Array.from(grouping) // => [ ... ]
有更快的方法可以做到這一點,但一個好的起點是循環遍歷您的匹配結果和 append 項目(如果它不在列表中)。 請務必復制 object 否則您將更改原始值。
uniqueProducts = products.reduce((result,item)=> {
var hit = 0;
for(var idx=0; idx<result.length; idx++) {
if (result[idx].id == item.id) {
hit += 1;
result[idx].orderAmount += item.orderAmount;
idx = result.length;
}
}
if (hit === 0) {
result.push(Object.assign({},item));
}
return result;
},[]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.