最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

arrays - Javascript object sum value based on properties effeicently - Stack Overflow

programmeradmin1浏览0评论

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.

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.

Share Improve this question edited May 21, 2013 at 14:47 arnold asked May 21, 2013 at 14:41 arnoldarnold 1,7129 gold badges25 silver badges31 bronze badges 7
  • 1 What are you adding in this? Can you update your question to be a bit more descriptive? – David Ziemann Commented May 21, 2013 at 14:44
  • 1 Ahhh. I see. It is a bit unclear in your question, but you basically want to add all similar keys. – David Ziemann Commented May 21, 2013 at 14:45
  • Can you still change the array to items containing: {'date':"2013-03-02T00:00",value:300} This will make it easier to group the items and and add values as you can sort the array on date and get same values in one clear swoop. – HMR Commented May 21, 2013 at 14:46
  • Well, you can use Array.map().. – techfoobar Commented May 21, 2013 at 14:46
  • @DavidZiemann only a bit? – Yatrix Commented May 21, 2013 at 14:46
 |  Show 2 more ments

3 Answers 3

Reset to default 4
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 :)

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 plicated 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));

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./documentcloud/underscore

发布评论

评论列表(0)

  1. 暂无评论