Как рассчитать среднее значение в JavaScript заданных свойств в массиве объектов - PullRequest
3 голосов
/ 27 марта 2019

У меня есть массив объектов. Каждый объект содержит несколько свойств, и одним из этих свойств является age.

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
]

Я хочу вычислить среднее значение для всех возрастных свойств в этом массиве. Я использую эту функцию:

let getAverage = arr => {
  let reducer = (total, currentValue) => total + currentValue;
  let sum = arr.reduce(reducer)
  return sum / arr.length;
}

Отлично работает для простого массива, подобного [22, 34, 12], но не для массивов объектов.

Как изменить мою функцию getAverage, чтобы она работала также с массивами объектов?

Вот фрагмент с моим кодом: https://jsfiddle.net/marektchas/kc8Ls0f5/2/

Ответы [ 5 ]

4 голосов
/ 27 марта 2019

Вы можете использовать reduce() и добавить свойство age каждого объекта в массиве к ac.Не забудьте передать 0 (начальное значение ac) в качестве второго аргумента, в противном случае он вернет NaN

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
]

let avgs = people.reduce((ac,a) => a.age + ac,0)/people.length
console.log(avgs)
3 голосов
/ 27 марта 2019

Вам не нужно изменять getAverage - вы можете предварительно обработать массив перед его передачей, в этом случае getAverage будет работать именно так, как нужно:

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
]

let getAverage = arr => {
  let reducer = (total, currentValue) => total + currentValue;
  let sum = arr.reduce(reducer)
  return sum / arr.length;
}

let ages = people.map(person => person.age);

console.log(getAverage(ages));

Если вы хотите изменить getAverage, чтобы он мог обрабатывать любой потенциальный тип ввода, тогда вы можете добавить необязательный аргумент, который будет выполнять извлечение значения, поэтому вы не сможетене нужно запускать map для каждого массива.

var numbers = [
  1,
  2,
  3,
  4,
  5
]

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
]

var moreComplexObjects = [
  { 
    a: {
      b: {
        c: 6
      }
    }
  },
  { 
    a: {
      b: {
        c: 7
      }
    }
  },
  { 
    a: {
      b: {
        c: 8
      }
    }
  }
]

//the default value of the second parameter is a function that returns the input
let getAverage = (arr, valueExtractor = x => x) => { 

  //extract the value of each element
  let reducer = (total, currentValue) => total + valueExtractor(currentValue);
  let sum = arr.reduce(reducer, 0) //make sure you add an initialiser
  return sum / arr.length;
}

const ageExtractor = person => person.age;
const complexKeyExtractor = obj => obj.a.b.c;

console.log(getAverage(numbers));
console.log(getAverage(people, ageExtractor));
console.log(getAverage(moreComplexObjects, complexKeyExtractor));

Примечание для вышеперечисленного: если вы не предоставите второй параметр для Array#reduce, затем first время выполнения total будет первым элементом массива, однако время second и далее будет суммой.Не стоит разбираться с этим случаем, так что ввод исходного значения решает его.

2 голосов
/ 27 марта 2019

Вы можете предоставить функцию для требуемого свойства и уменьшить ее начальным значением.

const
    getAverage = (array, fn = v => v) => {
        var reducer = fn => (total, item) => total + fn(item),
            sum = array.reduce(reducer(fn), 0);
        return sum / array.length;
    };

var people = [{ name: 'Anna', age: 22 }, { name: 'Tom', age: 34 }, { name: 'John', age: 12 }];

console.log(getAverage(people, o => o.age));
2 голосов
/ 27 марта 2019

Мы можем использовать Array.reduce для вычисления суммы, где acc - накопленная сумма, а отдельные объекты деструктурированы до переменной age, а затем вычислить среднее значение путем деления суммы на длину массива:

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
];

function getAvg(arr){
 return (people.reduce((acc, {age}) => (acc + age), 0))/arr.length;
}
console.log(getAvg(people));

Мы также можем сопоставить функцию свойству age и вычислить сумму, соединив массив в строку и оценив ее внутри конструктора Function:

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
];

function getAvg(arr){
 return (new Function(`return ${people.map(({age}) => age).join("+")}`)()) / arr.length;
}
console.log(getAvg(people));
1 голос
/ 27 марта 2019

Более упрощенный код

просто выполнить как getAverage (people.map (p => p.age)); используя ваш код

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
];

let getAverage = arr => {
  let reducer = (total, currentValue) => total + currentValue;
  let sum = arr.reduce(reducer)
  return sum / arr.length;
};

console.log(getAverage(people.map(p=> p.age)));
...