Summarize array of objects and calculate average value for each unique object name

前端 未结 6 1687
忘了有多久
忘了有多久 2020-12-17 02:31

I have an array like so:

var array = [
     {
       name: \"a\",
       value: 1 
     },
     {
       name: \"a\",
       value: 2 
     },
     {
                


        
相关标签:
6条回答
  • 2020-12-17 03:15

    You can do it with Alasql library with one line of code:

    var newArray = alasql('SELECT name, AVG([value]) AS [value] FROM ? GROUP BY name',
                           [array]);
    

    Here I put "value" in square brackets, because VALUE is a keyword in SQL.

    Try this example at jsFiddle

    0 讨论(0)
  • 2020-12-17 03:16

    October 2020, I think this is the shortest way (ES6+)

    const getAveragesByGroup = (arr, key, val) => {
      const average = (a, b, i, self) => a + b[val] / self.length;
      return Object.values(
        arr.reduce((acc, elem, i, self) => (
            (acc[elem[key]] = acc[elem[key]] || {
              [key]: elem[key],
              [val]: self.filter((x) => x[key] === elem[key]).reduce(average, 0),
            }),acc),{})
      );
    };
    
    console.log(getAveragesByGroup(array, 'name', 'value'))
    

    Try by yourself :)

    0 讨论(0)
  • 2020-12-17 03:26

    Here is a ES2015 version, using reduce

     let arr = [
      { a: 1, b: 1 },
      { a: 2, b: 3 },
      { a: 6, b: 4 },
      { a: 2, b: 1 },
      { a: 8, b: 2 },
      { a: 0, b: 2 },
      { a: 4, b: 3 }
    ]
    
    arr.reduce((a, b, index, self) => {
     const keys = Object.keys(a)
     let c = {} 
    
     keys.map((key) => {
      c[key] = a[key] + b[key]
    
      if (index + 1 === self.length) {
        c[key] = c[key] / self.length
      }
     })
    
     return c
    })
    
    0 讨论(0)
  • 2020-12-17 03:29

    You'll have to loop through the array, computing the sum and counts for each object. Here's a quick implementation:

    function average(arr) {
        var sums = {}, counts = {}, results = [], name;
        for (var i = 0; i < arr.length; i++) {
            name = arr[i].name;
            if (!(name in sums)) {
                sums[name] = 0;
                counts[name] = 0;
            }
            sums[name] += arr[i].value;
            counts[name]++;
        }
    
        for(name in sums) {
            results.push({ name: name, value: sums[name] / counts[name] });
        }
        return results;
    }
    

    Demonstration

    Note, this kind of thing can be made much easier if you use a library like Underscore.js:

    var averages = _.chain(array)
                    .groupBy('name')
                    .map(function(g, k) {
                        return { 
                            name: k, 
                            value: _.chain(g)
                                    .pluck('value')
                                    .reduce(function(x, y) { return x + y })
                                    .value() / g.length
                        };
                    })
                    .value();
    

    Demonstration

    0 讨论(0)
  • 2020-12-17 03:34
    var array = [
         {
           name: "a",
           value: 1 
         },
         {
           name: "a",
           value: 2 
         },
         {
           name: "a",
           value: 3 
         },
         {
           name: "b",
           value: 0 
         },
         {
           name: "b",
           value: 1 
         }
     ];
    var sum = {};
    for(var i = 0; i < array.length; i++) {
        var ele = array[i];
        if (!sum[ele.name]) {
            sum[ele.name] = {};
            sum[ele.name]["sum"] = 0;
            sum[ele.name]["count"] = 0;
        }
        sum[ele.name]["sum"] += ele.value;
        sum[ele.name]["count"]++;
    }
    var result = [];
    for (var name in sum) {
        result.push({name: name, value: sum[name]["sum"] / sum[name]["count"]});
    }
    console.log(result);
    
    0 讨论(0)
  • 2020-12-17 03:34

    And a possible solution using ECMA5 (as we seem to be missing one)

    var sums = {},
        averages = Object.keys(array.reduce(function (previous, element) {
            if (previous.hasOwnProperty(element.name)) {
                previous[element.name].value += element.value;
                previous[element.name].count += 1;
            } else {
                previous[element.name] = {
                    value: element.value,
                    count: 1
                };
            }
    
            return previous;
        }, sums)).map(function (name) {
            return {
                name: name,
                average: this[name].value / this[name].count
            };
        }, sums);
    

    On jsFiddle

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