Книга: JavaScript. Подробное руководство, 6-е издание

8.8.1. Обработка массивов с помощью функций

8.8.1. Обработка массивов с помощью функций

Представим, что у нас имеется массив чисел и нам необходимо найти среднее значение и стандартное отклонение для этих значений. Эту задачу можно было бы решить без использования приемов функционального программирования, как показано ниже:

var data = [1,1,3,5,5]; // Массив чисел
// Среднее - это сумма значений элементов, деленная на их количество
var total = 0;
for(var і = 0; і < data.length; і++) total += data[i];
var mean = total/data.length; // Среднее значение равно З
// Чтобы найти стандартное отклонение, необходимо вычислить сумму квадратов
// отклонений элементов от среднего,
total = 0;
for(var і = 0; і < data.length; i++) {
  var deviation = data[i] - mean;
  total += deviation * deviation;
}
var stddev = Math.sqrt(total/(data.length-1)); // Стандартное отклонение = 2

Те же вычисления можно выполнить в более кратком функциональном стиле, задействовав методы массивов mар() и reduce(), как показано ниже (краткое описание этих методов приводится в разделе 7.9):

// Для начала необходимо определить две простые функции
var sum = function(x,у) { return х+у; };
var square = function(x) { return x*x; };
// Затем использовать их совместно с методами класса Array для вычисления
// среднего и стандартного отклонения
var data = [1,1,3,5,5];
var mean = data.reduce(sum)/data.length;
var deviations = data.map(function(x) {return x-mean;});
var stddev = Math.sqrt(deviations.map(square).reduce(sum)/(data.length-1));

A как быть, если в нашем распоряжении имеется только реализация ЕСМА-Script 3, где отсутствуют эти новейшие методы массивов? Можно определить собственные функции mар() и reduce(), которые будут использовать встроенные методы при их наличии:

// Вызывает функцию f для каждого элемента массива и возвращает массив результатов.
// Использует метод Array.prototype.mар, если он определен,
var mар = Array.prototype.тар
    ? function(a, f) { return a.map(f); } // Если метод map() доступен
    : function(a,f) { // Иначе реализовать свою версию
  var results = [];
  for(var і = 0, len = a.length; і < len; і++) {
    if (і in a) results[i] = f.call(null, a[i], і, a);
  }
  return results;
};
// Выполняет свертку массива в единственное значение, используя функцию f
// и необязательное начальное значение. Использует метод Array.prototype.reduce,
// если он определен.
var reduce = Array.prototype.reduce
  ? function(a, f, initial) { // Если метод reduce() доступен,
    if (arguments.length > 2)
      return a.reduce(f, initial); // Если указано начальное значение,
    else return a.reduce(f); // Иначе без начального значения.
  }
  : function(a, f, initial) { // Этот алгоритм взят из спецификации ES5
  var і = 0, len = a.length, accumulator;
  // Использовать указанное начальное значение или первый элемент а
  if (arguments.length > 2)
    accumulator = initial;
  else { // Найти первый элемент массива с определенным значением
    if (len == 0) throw TypeError();
    while(i < len) {
      if (i in a) {
        accumulator = a[i++];
        break;
      }
      else i++;
    }
 

    if (i == len) throw TypeError();
  }
  // Теперь вызвать f для каждого оставшегося элемента массива
  while(i < len) {
    if (і in а)
      accumulator = f.call(undefined, accumulator, a[i], i, a);
    i++;
  }
  return accumulator;
};

После определения этих функций map() и reduce() вычисление среднего и стандартного отклонения будет выглядеть так:

var data = [1,1,3,5,5];
var sum = function(x.y) { return x+y; };
var square = function(x) { return x*x; };
var mean = reduce(data, sum)/data.length;
var deviations = map(data, function(x) {return x-mean;});
var stddev = Math.sqrt(reduce(map(deviations, square), sum)/(data.length-1));

Оглавление книги


Генерация: 4.036. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз