在对象数组中具有相同对象属性的javascript对象属性值

时间:2013-10-07 19:45:15

标签: javascript arrays json object reduce

如何使用javascript数组对象,例如:

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

并通过对值进行求和来合并重复键。 为了得到这样的东西:

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

我已尝试迭代并添加到新数组,但这不起作用:

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

11 个答案:

答案 0 :(得分:11)

您应该使用.key属性将未找到的每个对象分配给结果。

如果找到,则需要添加.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]);

此外,部分问题是您重复使用item变量来引用.key的值,因此您丢失了对该对象的引用。

答案 1 :(得分:6)

您可以直接使用mapreduce来代替使用for循环和推送值:

&#13;
&#13;
set1
&#13;
&#13;
&#13;

答案 2 :(得分:5)

您可以使用哈希表进行key分组。

&#13;
&#13;
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);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

另一种方法是收集Map中的所有键/值对,并使用Array.from格式化最终数组并对对象进行回调。

&#13;
&#13;
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);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 3 :(得分:4)

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/

答案 4 :(得分:1)

尝试一下,应该有帮助

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

以下是仅使用一个循环(while循环)的另一种解决方案:

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

答案 5 :(得分:1)

比其他地方发布的减少更简单

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

const output = objArr.reduce((accumulator, cur) => {
  let date = cur.key;
  let found = accumulator.find(elem => elem.key === date)
  if (found) found.val += cur.val;
  else accumulator.push(cur);
  return accumulator;
}, []);

console.log(output)

答案 6 :(得分:0)

这是您的替代方案,但与Explosion Pills类似,重用原始数组而不是创建新数组或不同对象。这种排序可能没有必要,会使事情变慢一些,但可以将其删除。

的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

jsperf将此(有和没有排序)与已接受的答案进行比较。您可以通过扩展数据集来改进性能测试。

答案 7 :(得分:0)

你也可以尝试使用javascript linq框架,它与sql语句完全相同,sql语句给出了所需的输出,编写的代码更少,有效,可在linq.js找到

&#13;
&#13;
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);
&#13;
<script src="http://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>
&#13;
&#13;
&#13;

与循环相比,这非常简单。 我希望这可能有所帮助。

答案 8 :(得分:0)

最近,我需要类似的实现,并且使用了某些使用reduce函数的家伙提供的类似解决方案。几天后,我想自己实现类似的东西,结果就是了。

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

输出:

[ { name: 'ernest', spent: 80 }, { name: 'astrit', spent: 3000 }, { name: 'besart', spent: 4140 } ]

答案 9 :(得分:0)

function mergeDuplicatesBy(array, getKey, mergeWith) {
  const buff = {}
  array.forEach(function (arrayElement) {
    const key = getKey(arrayElement)
    const alreadyExistingVal = buff[key]
    if (alreadyExistingVal) {
      buff[key] = mergeWith(alreadyExistingVal, arrayElement)
    } else {
      buff[key] = arrayElement
    }
  })
  return Object.values(buff)
}

mergeDuplicatesBy(
  arr,
  x => x.name,
  (x, y) => ({ name: x.name, foo: x.foo + y.foo })
)

答案 10 :(得分:0)

可以将 Array#reduce 与对象一起使用来存储每个键的值。

let arr = [{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}];
let res = Object.values(arr.reduce((acc, curr)=>{
  (acc[curr.key] = acc[curr.key] || {key: curr.key, val: 0}).val += curr.val;
  return acc;
}, {}));
console.log(res);

在较新的浏览器中,可以使用 logical nullish assignment

let arr = [{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}];
let res = Object.values(arr.reduce((acc, curr)=>{
  (acc[curr.key] ??= {key: curr.key, val: 0}).val += curr.val;
  return acc;
}, {}));
console.log(res);

相关问题