Sum javascript object propertyA values with same object propertyB in array of objects

前端 未结 9 2489
醉梦人生
醉梦人生 2020-11-22 04:48

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         


        
相关标签:
9条回答
  • 2020-11-22 05:18

    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);
            }
        }
    
    0 讨论(0)
  • 2020-11-22 05:22

    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 } ]
    
    0 讨论(0)
  • 2020-11-22 05:29

    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.

    0 讨论(0)
  • 2020-11-22 05:31

    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.

    0 讨论(0)
  • 2020-11-22 05:32

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

    0 讨论(0)
  • 2020-11-22 05:37

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

    0 讨论(0)
提交回复
热议问题