Reputation: 1712
I do have three objects inside an array in JS like below
[{"2013-03-02T00:00": 300}, {"2013-03-01T00:00": 200},{"2013-03-02T00:00": 50}]
I want something like below as output from the above array.
[{"2013-03-02T00:00": 350} , {"2013-03-01T00:00": 200}]
It can be done by looping through and adding, are there any efficient way I can do it?
Thanks in advance.
Upvotes: 3
Views: 3955
Reputation: 39280
If you can add the key "date" as another value of the object you can sort and group it, this will be quicker and more optimized when you have more values in the array.
[UPDATE]: fixed a little bug.
var arr = [{"date":"2013-03-02T00:00",val: 300}
, {"date":"2013-03-01T00:00",val: 200}
,{"date":"2013-03-02T00:00",val: 50}];
function groupArray(arr){
if(arr.length===0){return [];}
var pref,i;
// sort by date
arr.sort(function(a,b){
return (a.date>b.date)?1:(a.date<b.date)?-1:0;
});
// loop through the array grouping objects by date
pref=arr[0].date;
for(i=1;i<arr.length;i++){
if(arr[i].date===pref){
//set the total
arr[i-1].val=arr[i-1].val+arr[i].val;
//remove the element
arr.splice(i,1);
// set i one back
i--;
}
pref=arr[i].date;
}
return arr;
}
console.log(groupArray(arr));
A more complicated example is when you dynamically want to provide the key to sort on, in the example above the key is "hard coded" to be date but you maybe need to group on another key value, the following is a piece of code I had laying around that I've simplified to group by one key (original used an array of keys). You can pass a onMerge variable that should be a function that handles how to merge 2 items. This function is not generic and is specific to adding the val properties of the to be merged objects.
var arr = [{"date":"2013-03-02T00:00",val: 300}
, {"date":"2013-03-01T00:00",val: 200}
, {"date":"2013-03-01T00:00",val: 200}
, {"date":"2013-03-01T00:00",val: 200}
, {"date":"2013-03-01T00:00",val: 200}
,{"date":"2013-03-02T00:00",val: 50}];
/**
* @param arr is the array to be merged
* @param key is the key to use for merge
* (like date) will merge on items with same
* date value
* @param onMerge function to call when 2 items
* are merged with the 2 items as parameters
**/
function groupArray(arr,key,onMerge){
if(arr.length===0){return [];}
var pref,i;
// sort by key
arr.sort(function(a,b){
return (a[key]>b[key])?1:(a[key]<b[key])?-1:0;
});
// loop through the array grouping objects by key
pref=arr[0][key];
for(i=1;i<arr.length;i++){
if(arr[i][key]===pref){
//merge 2 items, call the onMerge callback
arr[i-1]=onMerge(arr[i-1],arr[i]);
//remove the element
arr.splice(i,1);
// set i one back
i--;
}
pref=arr[i][key];
}
return arr;
}
// functon that will be called when 2 items are merged
// stay will stay and gone will be gone
// this function is specific to your data type
function onMergeCallback(stay,gone){
stay.val=stay.val+gone.val;
return stay;
}
console.log(groupArray(arr,"date",onMergeCallback));
Upvotes: 1
Reputation: 13558
var myList = [{"2013-03-02T00:00": 300}, {"2013-03-01T00:00": 200},{"2013-03-02T00:00": 50}];
var result = {};
var item = null, key = null;
for(c=0; c<myList.length; c++) {
item=myList[c];
key = Object.keys(item)[0];
item=item[key];
if(!result[key]) result[key] = item;
else result[key] += item;
}
console.log(result);
I leave it as an exercise for the reader to put the result into the requested form. (after all you should solve at least some part of your problem yourself :)
Upvotes: 4
Reputation: 13188
You might want to have a look at underscore.js, which has implementations for a lot of helpful, efficient functions for manipulating and dealing with data. Specifically, you'd want to have a look at the _.groupBy
function:
var data = [{"2013-03-02T00:00": 300}, {"2013-03-01T00:00": 200},{"2013-03-02T00:00": 50}]
_.groupBy(data, function(obj) { return Object.keys(obj)[0]; })
You'd still have to iterate and sum the values, but that's why we have reduce functions!
If you want something more specific to your use case, I would have a look at the source on github.
https://github.com/documentcloud/underscore
Upvotes: 0