Как найти сумму массива чисел

810

Учитывая массив [1, 2, 3, 4], как я могу найти сумму его элементов? (В этом случае сумма будет 10.)

Я подумал, что это $.eachможет быть полезно, но я не уверен, как это реализовать.

akano1
источник
4
Этот вопрос находится на стадии обсуждения
Призрак Мадары
19
@ tereško Нежелание Google не является уважительной причиной для Stackoverflow. Пожалуйста, понизьте рейтинг, если вы чувствуете, что вопрос не был хорошо изучен. (Также, судя по ответам - это, кажется, очень противоречивая тема со многими возможными решениями, в том числе с некоторыми высоко оцененными плохими практиками (eval) - удивительно.)
Trilarion
8
Примечание: большинство ответов здесь по существу вычисляются a[0] + a[1] + ..., что может превратиться в конкатенацию строк, если массив содержит нечисловые элементы. Например ['foo', 42].reduce((a,b)=>a+b, 0) === "0foo42".
Бени Чернявский-Паскин
Нет встроенного редуктора, который можно было бы подать на Array.reduce? Думая что-то вроде [1,2,3].reduce(Math.sum).
Фил

Ответы:

545

Рекомендуется (уменьшить со значением по умолчанию)

Array.prototype.reduce может использоваться для перебора массива, добавляя текущее значение элемента к сумме предыдущих значений элемента.

console.log(
  [1, 2, 3, 4].reduce((a, b) => a + b, 0)
)
console.log(
  [].reduce((a, b) => a + b, 0)
)

Без значения по умолчанию

Вы получаете TypeError

console.log(
  [].reduce((a, b) => a + b)
)

До функций стрелок ES6

console.log(
  [1,2,3].reduce(function(acc, val) { return acc + val; }, 0)
)

console.log(
  [].reduce(function(acc, val) { return acc + val; }, 0)
)

Нечисловые входы

Если не-числа являются возможными входами, вы можете с этим справиться?

console.log(
  ["hi", 1, 2, "frog"].reduce((a, b) => a + b)
)

let numOr0 = n => isNaN(n) ? 0 : n

console.log(
  ["hi", 1, 2, "frog"].reduce((a, b) => 
    numOr0(a) + numOr0(b))
)

Не рекомендуемое опасное использование

Мы можем использовать eval для выполнения строкового представления кода JavaScript. Используя функцию Array.prototype.join для преобразования массива в строку, мы меняем [1,2,3] на «1 + 2 + 3», что соответствует 6.

console.log(
  eval([1,2,3].join('+'))
)

//This way is dangerous if the array is built
// from user input as it may be exploited eg: 

eval([1,"2;alert('Malicious code!')"].join('+'))

Конечно, отображение предупреждения - не самое страшное, что может случиться. Единственная причина, по которой я это включил, это ответ Ортунда на вопрос, так как я не думаю, что он был прояснен.

OwChallie
источник
8
Вы знаете, что эта магия reduce()все еще на 25-30% медленнее, чем простой индексированный for()цикл после долгих лет? jsperf.com/reduce-vs-loop/4
tevemadar
Между прочим, это приводит к проблемам, если число равно «0» - по любой причине его можно интерпретировать как строку. Добавление 1 * a + 1 * b работало на меня. Что касается скорости, это было легче написать, и мне наплевать на скорость
Питер Кей
1179

В Лиспе это было бы именно работой для reduce. Вы бы увидели такой код:

(reduce #'+ '(1 2 3)) ; 6

К счастью, в JavaScript у нас тоже есть reduce! К сожалению, +это оператор, а не функция. Но мы можем сделать это красиво! Вот, посмотрите:

const sum = [1, 2, 3].reduce(add,0); // with initial value to avoid when the array is empty

function add(accumulator, a) {
    return accumulator + a;
}

console.log(sum); // 6

Разве это не красиво? :-)

Даже лучше! Если вы используете ECMAScript 2015 (он же ECMAScript 6 ), это может быть довольно красиво:

const sum = [1, 2, 3].reduce((partial_sum, a) => partial_sum + a,0); 
console.log(sum); // 6
Флориан Маргейн
источник
28
Предполагая, что мы все используем ES2015, мы можем сделать его менее многословным:[1, 2, 3].reduce((a,b)=>a+b)
Денис Сегюре
1
Интересно, сравнимо ли время выполнения приведения с помощью функции (a, b) с ручной итерацией и суммированием или есть какие-то значительные накладные расходы?
Триларион
1
Я считаю, что стоит упомянуть, что ответ на самом деле можно найти на странице, на которую вы ссылаетесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Алекс Кон,
2
Я бы добавил пару методов в массив:Array.prototype.sum = function() { return this.reduce((a,b) => a+b, 0); } Array.prototype.avg = function() { return this.reduce((a,b) => a+b, 0)/this.length; }
пилат
2
@ Black это уменьшает массив в одно значение.
Флориан Маргейн
205

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

var a = [1,2,3];
var sum = a.reduce(function(a, b) { return a + b; }, 0);
Кейси Родармор
источник
3
IE8 не поддерживает его, и, похоже, jQuery не собирается его добавлять. Однако, у Прототипа есть это.
Измаил Смирноу
4
@Ishmael, вы можете использовать UnderscoreJS, который обращается к реализации браузера, если она доступна, или реализует свою собственную в противном случае.
Пабло Диаз
3
Что нелогично reduce()?
канон
3
@ s4nji Array.prototype.reduce() уменьшает массив до одного возвращаемого значения.
канон
6
@ s4nji ... если только вы не уменьшаете соус - в этом случае вы сводите его к основам, то есть к сумме всех вкусов без воды. :-)
CB Du Rietz
97
var arr = [1,2,3,4];
var total=0;
for(var i in arr) { total += arr[i]; }
янтарный
источник
3
Это намного быстрее, чем решение jQuery.each () выше.
Злой Дэн
41
@Sprog: Тем не менее, использование (var i=0; i<arr.length; i++)еще быстрее. И даже тогда использование var sum=0; var i=arr.length; while(i--) sum += arr[i]еще быстрее.
Riking
14
Использование for... inциклов в массивах работает в этом случае _ по совпадению_ и потому, что массивы расширяют объекты. Решение Рикинга лучше
Бенджамин Грюнбаум
2
@BenjaminGruenbaum при условии, что ничто не добавило перечислимые свойства в прототип массива ...
canon
1
@ YSC нет, это не так. for...inЦикл в JavaScript имеет индексы, что является общим камнем преткновения для кодеров , которые ожидают получить значения. (Попробуйте for(var i in [1,2,3]) { console.log(i); }в консоли.)
Янтарь
61
var total = 0;
$.each(arr,function() {
    total += this;
});
Тайлер Картер
источник
87
Пожалуйста, пожалуйста, используйте ответ reduceниже; не объявляйте изменяемые переменные, когда у вас их тоже нет.
Бруно Гридер
9
Этот ответ находится в стадии обсуждения
Призрак Мадары
11
Пожалуйста, не используйте это, даже если это «принятый ответ»; ответ Флориана ниже намного лучше!
Энди Синклер
12
@BrunoGrieder «Не объявляйте изменяемые переменные, когда вам не нужно» - это чрезвычайно предвзятое мнение о императивном языке , едва ли оно пахнет кодом из-за какого-либо натяжения воображения. В ответе Тайлера нет ничего плохого, и единственное отличие между Тайлером и Флорианом - это стиль.
Роб
5
От ОП: Я думал, что $ .each может быть полезным, но я не уверен, как это реализовать. Это может быть не лучшим, но ответить на запрос ОП.
33

Если вы используете Lodash, вы можете использовать функцию суммы

array = [1, 2, 3, 4];
sum = _.sum(array); // sum == 10
Дэвид говорит восстановить Монику
источник
29

Это возможно путем циклического sumперебора всех элементов и добавления их на каждой итерации в переменную -var.

var array = [1, 2, 3];

for (var i = 0, sum = 0; i < array.length; sum += array[i++]);

JavaScript не знает блоковую область видимости, поэтому sumбудет доступен:

console.log(sum); // => 6

То же, что и выше, однако аннотировано и подготовлено в виде простой функции:

function sumArray(array) {
  for (
    var
      index = 0,              // The iterator
      length = array.length,  // Cache the array length
      sum = 0;                // The total amount
      index < length;         // The "for"-loop condition
      sum += array[index++]   // Add number on each iteration
  );
  return sum;
}
yckart
источник
12
Будучи умным, я нашел бы код, декларирующий sumвне цикла, гораздо более читабельным.
Бени Чернявский-Паскин
@ BeniCherniavsky-Paskin Да, то же самое здесь ... Не знаю, почему я сделал это таким образом в тот день ... Тем не менее, я позволю этому как есть! Это просто пример того, как мы могли бы ... ;)
yckart
Начиная с ES6, javascript ДОЛЖЕН знать область видимости с constи let. Таким образом, вы можете объявить sumвне forцикла как let sum = 0;. Вы также можете кэшировать длину массива перед циклом какconst length = array.length;
KSK
23
arr.reduce(function (a, b) {
    return a + b;
});

Ссылка: Array.prototype.reduce ()

onhout
источник
6
Это не удастся, если arrесть [].
7
Добавьте значение по умолчанию, например, так:arr.reduce(function (a, b) { return a + b; }, 0);
Ngz
15
// Given array 'arr'
var i = arr.length;
var sum = 0;
while (--i) sum += arr[i];

Это займет в среднем 1,57 мс / прогон (измерено более 1000 прогонов на массиве из 100 случайных нормальных чисел), по сравнению с 3,604 мс / прогон с eval() описанным выше способом и 2,151 мс / прогон со стандартом для (i, length, ++) ) петля.

Примечание по методологии: этот тест был запущен на сервере скриптов Google Apps, поэтому его движки JavaScript в значительной степени совпадают с Chrome.

РЕДАКТИРОВАТЬ: --iвместо i--сохранения 0,12 мс каждый прогон (я-- 1,7)

РЕДАКТИРОВАТЬ: Святой ругань, не берите в голову весь этот пост. Используйте метод redu (), упомянутый выше, это всего 1 мсек / прогон.

Riking
источник
1
Я люблю время, которое вы использовали. Ваш ответ не просто говорит "Выбери меня, я лучший!" Вместо этого это показывает нам, почему . Во всяком случае, это while (--i) do_somethingможет работать и для других вещей.
Программы
var sum = arr[0]
noobninja
12

Вы также можете использовать ReduRight.

[1,2,3,4,5,6].reduceRight(function(a,b){return a+b;})

что приводит к выводу как 21.

Ссылка: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight

Рохит Бхалке
источник
Должно быть быстрее в chrome, потому что оптимизация к циклу javascript (т.е. уменьшение длины) также может быть применена к базовой сборке, чтобы она работала быстрее.
Джек Гиффин,
12

Кто-нибудь ищет функционального лайнера, как я? Возьми это:

sum= arr.reduce(function (a, b) {return a + b;}, 0);
Компьютерщик-кречет
источник
Вы можете добавить начальное значение для arr.reduce(function(a, b) { return a + b;}, 0);
Reduction
Спасибо! Я включу это.
geek-merlin
12

Хорошо, представьте, что у вас есть этот массив ниже:

const arr = [1, 2, 3, 4];

Давайте начнем искать много разных способов сделать это, так как я не смог найти здесь исчерпывающего ответа:

1) Использование встроенного метода limit ()

function total(arr) {
  if(!Array.isArray(arr)) return;
  return arr.reduce((a, v)=>a + v);
}

2) Использование для цикла

function total(arr) {
  if(!Array.isArray(arr)) return;
  let totalNumber = 0;
  for (let i=0,l=arr.length; i<l; i++) {
     totalNumber+=arr[i];
  }
  return totalNumber;
}

3) Использование цикла while

function total(arr) {
  if(!Array.isArray(arr)) return;
  let totalNumber = 0, i=-1;
  while (++i < arr.length) {
     totalNumber+=arr[i];
  }
  return totalNumber;
}

4) Использование массива forEach

function total(arr) {
  if(!Array.isArray(arr)) return;
  let sum=0;
  arr.forEach(each => {
    sum+=each;
  });
  return sum;
};

и назовите это так:

total(arr); //return 10

Не рекомендуется делать что-то подобное в Array ...

Алиреза
источник
11

Забавный подход:

eval([1,2,3].join("+"))
электрон
источник
5
Пожалуйста, не могли бы вы расширить этот ответ, объяснив, что происходит в этом коде? Почему это работает? Что именно это делает? Эти вещи помогают улучшить качество ответа.
Ортунд
@ user40521 уже ответил так, как я думаю. Я этого не видел.
электрон
Хотя это коротко и приятно, и, конечно, интересно, это также очень неэффективно. Использование reduceопределенно предпочтительнее в большинстве, если не во всех случаях.
Ниндзяканнон
Errm,[1,"2;YourProgram.ripToShreds();3",4]
Программы
Таким образом, я получаю, NaNкогда пытаюсь eval(['alert("removing your computer")',2,3].join("+"))неправильный ответ 0/10
pie6k
10

Стандартное решение JavaScript:

var addition = [];
addition.push(2);
addition.push(3);

var total = 0;
for (var i = 0; i < addition.length; i++)
{
    total += addition[i];
}
alert(total);          // Just to output an example
/* console.log(total); // Just to output an example with Firebug */

Это работает для меня (результат должен быть 5). Я надеюсь, что в таком решении нет скрытого недостатка.

нано
источник
1
Кроме того, любой программист на C или Java сможет понять это.
Аудрюс Мескаускас
для простого суммирования всех значений у простого простого цикла for нет конкурентов по времени выполнения
fedeghe
Единственная проблема, это немного раздражает, когда у вас есть 20 циклов for, все вложенные друг в друга
Redwolf Programs
7
var totally = eval(arr.join('+'))

Таким образом, вы можете поместить все виды экзотических вещей в массив.

var arr = ['(1/3)','Date.now()','foo','bar()',1,2,3,4]

Я только наполовину шучу.

user40521
источник
26
Я смеясь
caub
eval(['alert("removing your computer")',2,3].join("+"))
pie6k
7

Я новичок в JavaScript и кодировании в целом, но я обнаружил, что простой и легкий способ суммирования чисел в массиве выглядит так:

    var myNumbers = [1,2,3,4,5]
    var total = 0;
    for(var i = 0; i < myNumbers.length; i++){
        total += myNumbers[i];
    }

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

CandyPaintedRIMS
источник
1
Чем это отличается от этого ответа 2012 года или этого ответа 2014 года ? Есть два решения, которые вы еще не видели.
Дан Даскалеску
5

Короткий кусок кода JavaScript сделает эту работу:

var numbers = [1,2,3,4];
var totalAmount = 0;

for (var x = 0; x < numbers.length; x++) {

    totalAmount += numbers[x];
}

console.log(totalAmount); //10 (1+2+3+4)
Тимур Жиленков
источник
5

Несколько человек предложили добавить .sum()метод к Array.prototype. Обычно это считается плохой практикой, поэтому я не предлагаю вам это делать.

Если вы все еще настаиваете на этом, то это краткий способ написать это:

Array.prototype.sum = function() {return [].reduce.call(this, (a,i) => a+i, 0);}

тогда: [1,2].sum(); // 3

Обратите внимание, что функция, добавленная в прототип, использует смесь функций ES5 и ES6 и синтаксиса стрелок. functionОбъявляется , чтобы метод , чтобы получить thisконтекст от Arrayкоторый вы работаете на. Я использовал =>для краткости внутри reduceзвонка.

парень
источник
5

Используйте forцикл:

const array = [1, 2, 3, 4];
let result = 0;

for (let i = 0; i < array.length - 1; i++) {
  result += array[i];
}

console.log(result); // Should give 10

Или даже forEachцикл

const array = [1, 2, 3, 4];
let result = 0;

array.forEach(number => {
  result += number;
})

console.log(result); // Should give 10

Для простоты используйте reduce:

const array = [10, 20, 30, 40];
const add = (a, b) => a + b
const result = array.reduce(add);

console.log(result); // Should give 100
JuicY_Burrito
источник
4

Не надо initial value! Потому что, если no initial valueне передано, то callback functionпервый элемент списка не вызывается, а первый элемент вместо этого передается как initial value. Очень хорошая черта :)

[1, 2, 3, 4].reduce((a, x) => a + x) // 10
[1, 2, 3, 4].reduce((a, x) => a * x) // 24
[1, 2, 3, 4].reduce((a, x) => Math.max(a, x)) // 4
[1, 2, 3, 4].reduce((a, x) => Math.min(a, x)) // 1
Яс
источник
4

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

const getSum = arr => (arr.length === 1) ? arr[0] : arr.pop() + getSum(arr);

getSum([1, 2, 3, 4, 5]) //15

По сути, функция принимает массив и проверяет, содержит ли массив ровно один элемент. Если false, он выталкивает последний элемент из стека и возвращает обновленный массив.

Прелесть этого фрагмента в том, что функция включает arr[0]проверку для предотвращения бесконечного зацикливания. Как только он достигает последнего элемента, он возвращает всю сумму.

Рекс Лоу
источник
4

Вы можете объединить метод redu () с лямбда-выражением:

[1, 2, 3, 4].reduce((accumulator, currentValue) => accumulator + currentValue);
antonjs
источник
3

использование reduce

let arr = [1, 2, 3, 4];

let sum = arr.reduce((v, i) => (v + i));

console.log(sum);

Дэмиен Ассейя
источник
3

я видел, что все ответы идут на решение «уменьшить»

var array = [1,2,3,4]
var total = 0
for (var i = 0; i < array.length; i++) {
    total += array[i]
}
console.log(total)
Адриан Свифтер
источник
3

точность

Сортировать массив и начальную сумму из наименьших чисел (фрагмент показывает разницу с несортировкой)

[...arr].sort((a,b)=>a-b).reduce((a,c)=>a+c,0)

Для многомерного массива чисел используйте arr.flat(Infinity)

Камил Келчевски
источник
2

Крутые трюки здесь, у меня есть гниль с множеством безопасных традиционных ответов, не кэширующих длину массива.

function arraySum(array){
  var total = 0,
      len = array.length;

  for (var i = 0; i < len; i++){
    total += array[i];
  }

  return total;
};

var my_array = [1,2,3,4];

// Returns 10
console.log( arraySum( my_array ) );

Без кеширования длины массива JS-компилятору необходимо проходить через массив при каждой итерации цикла, чтобы вычислить длину, в большинстве случаев это лишние издержки. V8 и многие современные браузеры оптимизируют это для нас, так что это не так важно, как раньше, но есть более старые устройства, которые выигрывают от этого простого кэширования.

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

Вот ссылка CodePen для этой функции arraySum. http://codepen.io/brandonbrule/pen/ZGEJyV

Возможно, это устаревшее мышление, которое застряло у меня, но я не вижу недостатка в его использовании в этом контексте.

Брэндон Брюл
источник
Проблема кэширования длины - красная сельдь. Двигатели JS оптимизируют это для вас, не мигая.
2

Это действительно хорошие ответы, но на всякий случай, если числа в последовательности, как в вопросе (1,2,3,4), вы можете легко сделать это, применив формулу (n * (n + 1)) / 2 где n - последнее число

Сантош
источник
2
Object.defineProperty(Object.prototype, 'sum', {
    enumerable:false,
    value:function() {
        var t=0;for(var i in this)
            if (!isNaN(this[i]))
                t+=this[i];
        return t;
    }
});

[20,25,27.1].sum()                 // 72.1
[10,"forty-two",23].sum()          // 33
[Math.PI,0,-1,1].sum()             // 3.141592653589793
[Math.PI,Math.E,-1000000000].sum() // -999999994.1401255

o = {a:1,b:31,c:"roffelz",someOtherProperty:21.52}
console.log(o.sum());              // 53.519999999999996
ostranenie
источник
Этот код удаляет вашу операционную систему? Или он отправляет мне вашу личную информацию?
2

Это намного проще

function sumArray(arr) {
    var total = 0;
    arr.forEach(function(element){
        total += element;
    })
    return total;
}

var sum = sumArray([1,2,3,4])

console.log(sum)
Якуб Гавел
источник
2

Простой пример метода:

function add(array){
    var arraylength = array.length;
    var sum = 0;
    for(var timesToMultiply = 0; timesToMultiply<arraylength; timesToMultiply++){
        sum += array[timesToMultiply];
    }

    return sum;
}

console.log(add([1, 2, 3, 4]));
Sifiso Nkabinde
источник