Reputation: 3647
I have following array with me where records are shown per user
let data = [
{ userid: 1, placename: abc, price: 10 },
{ userid: 1, placename: pqr, price: 20 },
{ userid: 1, placename: xyz , price: 30},
{ userid: 2, placename: abc , price: 40},
{ userid: 2, placename: lmn , price: 50}
So, I want to transpose this data group by userid, by concatenation of place name and sum of price. It should be look like below
UseId PlaceName Price
1 abc,xyz,pqr 60
2 abc,lmn 90
And I am binding this data to bootstrap vue b-table component As of now I have done like this
groupby: function(array, key) {
const result = {};
array.forEach(item => {
if (!result[item[key]]) {
result[item[key]] = [];
}
result[item[key]].push(item);
});
return result;
},
And calling this while view is getting initialized,
groupby(this.list,'userid');
though I am getting all records in row as per user, but I am not able to concatenate the values and doing total.
While binding to table it is giving error 'Expected Arrat,got object'
Is anything missing here !
Any help on this appreciated !
Upvotes: 0
Views: 1707
Reputation: 1805
I split the solution in 3 steps, X, Y and Z:
X = group the rows by userid;
Y = concat the placenames and sum the prices;
Z = make a simpler object.
let data = [
{ userid: 1, placename: 'abc', price: 10 },
{ userid: 1, placename: 'pqr', price: 20 },
{ userid: 1, placename: 'xyz', price: 30 },
{ userid: 2, placename: 'abc', price: 40 },
];
const X = data.reduce((a, { userid, placename, price }) => { a[userid] = [...(a[userid] || []), { placename, price }]; return a }, {})
const Y = Object.entries(X).map(([userid, items]) => { return [userid, items.reduce((a, c) => { a.placename = [...a.placename.split(',').filter(s => !!s), c.placename].join(','); a.price += c.price; return a; }, { placename: '', price: 0 })]; });
const Z = Y.map(([userid, { placename, price }]) => ({ userid, placename, price }))
console.log(Z)
You can use a single line solution too:
let data = [
{ userid: 1, placename: 'abc', price: 10 },
{ userid: 1, placename: 'pqr', price: 20 },
{ userid: 1, placename: 'xyz', price: 30 },
{ userid: 2, placename: 'abc', price: 40 },
]
const doIt = (data) => Object.entries(data.reduce((a, { userid, placename, price }) => { a[userid] = [...(a[userid] || []), { placename, price }]; return a }, {})).map(([userid, items]) => { return [userid, items.reduce((a, c) => { a.placename = [...a.placename.split(',').filter(s => !!s), c.placename].join(','); a.price += c.price; return a; }, { placename: '', price: 0 })]; }).map(([userid, { placename, price }]) => ({ userid, placename, price }))
console.log(doIt(data))
Have fun!
Upvotes: 1
Reputation: 22227
Whenever you feel like making an empty object and using array.map to populate it, try using .reduce instead
const data = [
{ userid: 1, placename: "abc", price: 10 },
{ userid: 1, placename: "pqr", price: 20 },
{ userid: 1, placename: "xyz" , price: 30},
{ userid: 2, placename: "abc" , price: 40},
{ userid: 2, placename: "lmn" , price: 50}
];
const groupBy = (arr, key) => Object.values(
arr.reduce((acc, item) => {
const k = item[key];
if (!acc[k]) {
acc[k] = {...item};
} else {
acc[k].placename += "," + item.placename;
acc[k].price += item.price;
}
return acc;
}, {})
);
console.log(groupBy(data, "userid"));
Upvotes: 1
Reputation: 22524
You can group your array item based on userid
and push placename
into array and sum up price
for same userid
.
const data = [ { userid: 1, placename: 'abc', price: 10 }, { userid: 1, placename: 'pqr', price: 20 }, { userid: 1, placename: 'xyz' , price: 30}, { userid: 2, placename: 'abc' , price: 40}, { userid: 2, placename: 'lmn' , price: 50}],
result = Object.values(data.reduce((r,o) => {
r[o.userid] = r[o.userid] || {userid: o.userid, placename: [], price: 0};
r[o.userid].placename.push(o.placename);
r[o.userid].price += o.price;
return r;
},{}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation:
Try out to filter the items that have the same userid then join place names and sum their prices :
array.forEach(item => {
if (!result[item[key]]) {
result[item[key]] = [];
}
let matched=array.filter(el=>el.UseId===item.UseId);
result[item[key]].push(
{
UseId:item.UseId,
placeName:matched.map(e=>e.placename).join(),
Price:matched.reduce((a, b) => a + b.price, 0)
});//push end
});
Upvotes: 2