How would one take a javascript array of objects such as:
my objArr = [
{key:Mon Sep 23 2013 00:00:00 GMT-0400, val:42},
{key:Mon Sep 24 2013 00:00:00 GMT-04
Try this, it should help
var arr1 = [
{ name: 'besart', value: 12 },
{ name: 'astrit', value: 10 },
{ name: 'astrit', value: 10 },
{ name: 'besar', value: 18 },
{ name: 'besar', value: 3 },
{ name: 'astrit', value: 3 },
{ name: 'besart', value: 3 },
{ name: 'besart', value: 10 },
{ name: 'besar', value: 0 },
];
var arr2 = [];
var emri = "";
var value = 0;
for(var i = 0;i<arr1.length;i++){
emri=arr1[0].name;
value+=arr1[0].value;
for(var j=1;j<arr1.length;j++){
if(emri==arr1[j].name){
value+=arr1[j].value;
arr1.splice(j,1);
j--;
}
}
arr1.splice(0,1);
arr2[i] = {name:emri,value:value};
value=0;
}
console.log(arr2);
Below is another solution that uses only one loop (while loop):
var arr2 = [];
var emri = "";
var value = 0;
var i=1;
var j=0;
while(arr1.length != 0){
emri = arr1[0].name;
if(emri == arr1[i].name){
value+=arr1[i].value;
arr1.splice(i,1);
i--;
}
i++;
if(i==arr1.length){
value+=arr1[0].value;
i=1;
arr2[j]={name:emri,value:value};
j++;
value=0;
arr1.splice(0,1);
}
}
Recently l needed a similar implementation and l used a similar solution offered by some guy that used reduce function. Few days later i wanted to implement something similar by myself and here is the result.
const users = [
{ id: 1, name: 'ernest', spent: 40 },
{ id: 2, name: 'ernest', spent: 40 },
{ id: 3, name: 'astrit', spent: 22 },
{ id: 4, name: 'astrit', spent: 2956 },
{ id: 5, name: 'astrit', spent: 22 },
{ id: 6, name: 'besart', spent: 40 },
{ id: 7, name: 'besart', spent: 100},
{ id: 8, name: 'besart', spent: 4000 }
];
const sum = [];
users.forEach(el => {
if(sum.length === 0){
delete el.id;
sum.push(el);
}
else
{
const get = () => {
for(let i = 0; i < sum.length; i++){
if(sum[i].name === el.name ){
return { stat: true, id: i };
}
}
}
let i = get();
if(i){
sum[i.id].spent += el.spent;
}
else
{
delete el.id;
sum.push(el);
}
}
});
console.log(sum);
Output:
[ { name: 'ernest', spent: 80 }, { name: 'astrit', spent: 3000 }, { name: 'besart', spent: 4140 } ]
You should be assigning each object not found to the result with its .key
property.
If it is found, then you need to add its .val
.
var temp = {};
var obj = null;
for(var i=0; i < objArr.length; i++) {
obj=objArr[i];
if(!temp[obj.key]) {
temp[obj.key] = obj;
} else {
temp[obj.key].val += obj.val;
}
}
var result = [];
for (var prop in temp)
result.push(temp[prop]);
Also, part of the problem was that you were reusing the item
variable to reference the value of .key
, so you lost reference to the object.
Here is an alternative for you, but similar to that of Explosion Pills, reuses the original array rather than creating a new one or a different object. The sort may not be necessary and will slow things down a little, but it could be removed.
Javascript
function reduceMyObjArr(arr) {
var temp = {},
index;
for (index = arr.length - 1; index >= 0; index -= 1) {
key = arr[index].key;
if (temp.hasOwnProperty(key)) {
arr[temp[key]].val += arr[index].val;
arr.splice(index, 1);
} else {
temp[key] = index;
}
}
arr.sort(function (a, b) {
if (a.key === b.key) {
return 0;
}
if (a.key < b.key) {
return -1;
}
return 1;
});
return arr;
}
var myObjArr = [{
key: "Mon Sep 23 2013 00: 00: 00 GMT - 0400",
val: 42
}, {
key: "Mon Sep 24 2013 00: 00: 00 GMT - 0400",
val: 78
}, {
key: "Mon Sep 25 2013 00: 00: 00 GMT - 0400",
val: 23
}, {
key: "Mon Sep 23 2013 00: 00: 00 GMT - 0400",
val: 54
}];
reduceMyObjArr(myObjArr);
console.log(myObjArr);
jsFiddle
And a jsperf that compares this (with and without the sort) against the accepted answer. You can improve the performance test by extending the data set.
You could use a hash table for the grouping by key
.
var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}],
grouped = [];
array.forEach(function (o) {
if (!this[o.key]) {
this[o.key] = { key: o.key, val: 0 };
grouped.push(this[o.key]);
}
this[o.key].val += o.val;
}, Object.create(null));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another approach is to collect all key/value pairs in a Map and format the final array with Array.from and a callback for the objects.
var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54 }],
grouped = Array.from(
array.reduce((m, { key, val }) => m.set(key, (m.get(key) || 0) + val), new Map),
([key, val]) => ({ key, val })
);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Rather than using a for loop and pushing values, you can directly use map and reduce:
let objArr = [
{key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42},
{key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78},
{key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23},
{key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}
];
// first, convert data into a Map with reduce
let counts = objArr.reduce((prev, curr) => {
let count = prev.get(curr.key) || 0;
prev.set(curr.key, curr.val + count);
return prev;
}, new Map());
// then, map your counts object back to an array
let reducedObjArr = [...counts].map(([key, value]) => {
return {key, value}
})
console.log(reducedObjArr);