2013-10-07 8 views
6

Wie würde man eine Javascript-Array von Objekten nehmen wie:Sum Javascript Objekt propertyâ Werte mit demselben Objekt propertyB in Array von Objekten

my 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}] 

und Nachschlüssel fusionieren, indem die Werte summiert werden. Um so etwas zu bekommen:

my reducedObjArr = [ 
{key:Mon Sep 23 2013 00:00:00 GMT-0400, val:96}, 
{key:Mon Sep 24 2013 00:00:00 GMT-0400, val:78}, 
{key:Mon Sep 25 2013 00:00:00 GMT-0400, val:23}] 

Ich habe versucht, und in ein neues Array Hinzufügen laufen, aber das hat nicht funktioniert:

var reducedObjArr = []; 
var item = null, key = null; 
for(var i=0; i<objArr.length; i++) { 
    item=objArr[i]; 
    key = Object.keys(item)[0]; 
    item=item[key]; 

    if(!result[key]){ 
     result[key] = item; 
    }else{ 
     result[key] += item;} 
    }a 
+0

Warum tun Sie 'key = Object.keys (Artikel) [0]; item = Gegenstand [Schlüssel]; '? Sie wissen bereits, dass der Name 'key' ist, also tun Sie einfach' item.key' oder 'objArr [i] .key'. Wenn Sie den Index "[0]" verwenden, erhalten Sie nicht immer die gleiche Eigenschaft. – user2736012

Antwort

8

Sie sollte jedes Objekt, das nicht gefunden wurde, dem Ergebnis mit seiner .key Eigenschaft zuweisen. Wenn es gefunden wird, müssen Sie .val hinzufügen.

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

Auch ein Teil des Problems war, dass Sie die item Variable wurden die Wiederverwendung der Wert von .key, zu verweisen, so dass Sie Verweis auf das Objekt verloren.

3
var targetObj = {}; 
for (var i = 0; i < objArr.length; i++) { 
    if (!targetObj.hasOwnProperty(objArr[i].key)) { 
     targetObj[objArr[i].key] = 0; 
    } 
    targetObj[objArr[i].key] += objArr[i].val; 
} 

http://jsfiddle.net/HUMxp/

+0

OP möchte die gleichen Schlüssel/Wert-Paare, aber mit dem "val" konsolidiert. – user2736012

0

Hier ist eine Alternative für Sie, aber ähnlich der von Explosion Pills, verwendet das ursprüngliche Array, anstatt ein neues oder ein anderes Objekt zu erstellen. Die Art ist möglicherweise nicht notwendig und wird die Dinge ein wenig verlangsamen, aber sie könnte entfernt werden.

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

Und ein jsperf, die diese (mit und ohne die Art) gegen die akzeptierte Antwort vergleicht. Sie können den Leistungstest verbessern, indem Sie den Datensatz erweitern.

4

Anstatt einer for-Schleife und Schubwerte verwenden, können Sie direkt verwenden map und 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);

0

Sie auch Javascript Linq Rahmen versuchen können, mit der genau gleichen wie SQL-Anweisung was gegeben ist gewünschte Ausgabe mit weniger geschriebenen Code und effektiv und gefunden bei linq.js

var 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} 
 
]; 
 

 

 
var aggregatedObject = Enumerable.From(objArr) 
 
     .GroupBy("$.key", null, 
 
       function (key, g) { 
 
        return { 
 
         key: key, 
 
         contributions: g.Sum("$.val") 
 
        } 
 
     }) 
 
     .ToArray(); 
 

 
console.log(aggregatedObject);
<script src="http://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>

das ist ziemlich einfach, wie zu Schleifen zu vergleichen. ich hoffe, dass dies helfen kann.

3

Sie könnten eine Hash-Tabelle für die Gruppierung von key verwenden.

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