Reputation: 8918
I have the following array:
[
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 5,
"date": "2018-11-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 2,
"date": "2018-11-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 1,
"date": "2018-12-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 2,
"date": "2018-12-27T00:00:00.000Z",
}
]
And i want to merge the object based on idItem and date and calculate the average mark so i can have the following:
[
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 3.5,
"date": "2018-11-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 1.5,
"date": "2018-12-27T00:00:00.000Z"
}
]
Upvotes: 0
Views: 79
Reputation: 1942
First, I'll declare the array we will be using in this example:
var array = [
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 5,
"date": "2018-11-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 2,
"date": "2018-11-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 1,
"date": "2018-12-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 2,
"date": "2018-12-27T00:00:00.000Z",
}
];
So, here's the situation: I have one program that does work, but another implementation that almost works. I'll start with the one that does work, and it uses the alasql
library:
To load the dependency, use the following <script>
tag:
<script src="https://cdn.jsdelivr.net/npm/[email protected]">
Implementation:
var newArray = alasql('SELECT idItem, AVG([mark]) AS [mark], date AS [date]
FROM ? GROUP BY date',[array]);
console.log(JSON.stringify(newArray));
This next program only calculates the average mark for all IDs not taking into account the date (so the resulting average is 2.5). Perhaps someone can figure out how to properly run this program and edit my answer:
var sum = {};
for(var i = 0; i < array.length; i++) {
var ele = array[i];
if (!sum[ele.idItem]) {
sum[ele.idItem] = {};
sum[ele.idItem]["sum"] = 0;
sum[ele.idItem]["count"] = 0;
}
sum[ele.idItem]["sum"] += ele.mark;
sum[ele.idItem]["count"]++;
}
var result = [];
for (var idItem in sum) {
result.push({idItem: idItem, mark: sum[idItem]["sum"] / sum[idItem]["count"]});
}
console.log(JSON.stringify(result));
Upvotes: 0
Reputation: 22794
If id and date strings don't have a comma (,
) in them, then you can use this solution, I first generate an object where the keys are a concatenation of the id and the date, and the values are objects that have the number of elements that have the id and date of the key, and the sum of their marks, this object will then be used to construct the desired array:
var arr = [
{ "idItem": "5d656f10394d6524c821f1b1", "mark": 5, "date": "2018-11-27T00:00:00.000Z" },
{ "idItem": "5d656f10394d6524c821f1b1", "mark": 2, "date": "2018-11-27T00:00:00.000Z" },
{ "idItem": "5d656f10394d6524c821f1b1", "mark": 1, "date": "2018-12-27T00:00:00.000Z" },
{ "idItem": "5d656f10394d6524c821f1b1", "mark": 2, "date": "2018-12-27T00:00:00.000Z" }
];
var obj = {};
arr.forEach((o) => {
var k = o.idItem + ',' + o.date;
if (obj.hasOwnProperty(k)) {
obj[k].s += o.mark;
obj[k].n += 1;
} else {
obj[k] = {s: o.mark, n: 1};
}
});
var result = [];
Object.keys(obj).forEach((k) => {
var p = k.split(',');
result.push({idItem: p[0], date: p[1], mark: obj[k].s / obj[k].n})
});
console.log(result);
Upvotes: 1
Reputation: 3777
Try this:
const input = [
{ idItem: "5d656f10394d6524c821f1b1", mark: 5, date: "2018-11-27T00:00:00.000Z" },
{ idItem: "5d656f10394d6524c821f1b1", mark: 2, date: "2018-11-27T00:00:00.000Z" },
{ idItem: "5d656f10394d6524c821f1b1", mark: 1, date: "2018-12-27T00:00:00.000Z" },
{ idItem: "5d656f10394d6524c821f1b1", mark: 2, date: "2018-12-27T00:00:00.000Z" }
];
const ids = new Set(input.map(e => `${e.idItem} ${e.date}`));
const grouped = [...ids].map(id => input.filter(
e => `${e.idItem} ${e.date}` === id
)).map(
group => ({
...group[0],
mark: group.reduce((acc, cur) => cur.mark + acc, 0) / group.length,
})
);
You can see the result logged out here
Probably not the most performant, but it works. First we get a set of all the combinations of id and date, then filter the input for each combination. For each group we then copy the date and id over to the result, and reduce the entries to get the average.
Upvotes: 1
Reputation: 1681
Im using lodash groupBy.
Object.entries(_.groupBy([
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 5,
"date": "2018-11-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 2,
"date": "2018-11-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 1,
"date": "2018-12-27T00:00:00.000Z"
},
{
"idItem": "5d656f10394d6524c821f1b1",
"mark": 2,
"date": "2018-12-27T00:00:00.000Z",
}
], e => `${e.idItem}_${e.date}`)).reduce((acc, [key, value]) => {
const mark = value.reduce((sum, el) => sum + el.mark, 0) / value.length
const [idItem, date] = key.split('_')
return [...acc, { idItem, date, mark }]
}, [])
Upvotes: 1