2014-02-17 2 views
4

У меня есть массив следующим образом:Обобщить массив объектов и вычислить среднее значение для каждого уникального имени объекта

var array = [ 
    { 
     name: "a", 
     value: 1 
    }, 
    { 
     name: "a", 
     value: 2 
    }, 
    { 
     name: "a", 
     value: 3 
    }, 
    { 
     name: "b", 
     value: 0 
    }, 
    { 
     name: "b", 
     value: 1 
    } 
]; 

И мне нужен массив так:

var newarray = [ 
    { 
     name: "a", 
     value: 2 
    }, 
    { 
     name: "b", 
     value: 0.5 
    } 
] 

Если новый массив имеет каждое уникальное имя как объект со средним значением.

Есть ли простой способ достичь этого?

+0

Вы только хотите знать о '' Ā' и b'? –

+0

a и b являются просто примерами. Мой массив будет иметь больше имен, чем просто a и b. Как мои значения неверны? a имеет значения 1, 2 и 3. 1 + 2 + 3 = 6, для a существует 3 значения, поэтому 6/3 = 2. b имеет значения 0 и 1. 0 + 1 = 1, для значения 2 b, так что 1/2 = 0,5. – user3317337

+0

@ user3317337: извините, это была моя ошибка - я, хотя третий был для «b», а не «a». –

ответ

5

Вам придется проходить через массив, вычисляя сумму и подсчеты для каждого объекта. Вот быстрое внедрение:

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

Обратите внимание, что такого рода вещи можно сделать гораздо проще, если вы используете библиотеку как 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

Спасибо. Я ценю быстрый ответ и демонстрацию. – user3317337

+1

Я не знаю, что подчеркивающая версия «намного проще». Это требует понимания * chain *, * groupBy *, * map *, * pluck *, * value * и * reduce * plus требует подходящей функции для * reduce *. Готов поспорить, это также намного медленнее, чем версия POJS (что может быть более кратким). ;-) – RobG

+0

@ RobG Справедливая точка. Это проще, если вы предпочитаете стратегии функционального программирования. Я в основном хотел предложить альтернативу. –

2
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

И возможное решение с использованием ECMA5 (as мы, кажется, не хватает одного)

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

На jsFiddle

0

Вы можете сделать это с Alasql библиотекой с помощью одной строки кода:

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

Здесь я ставлю «значение» в квадратных скобках, потому что VALUE является ключевым словом в SQL.

Попробуйте this example на jsFiddle

0

Вот является ES2015 версия, с помощью уменьшения

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 
}) 
Смежные вопросы