TL;DR
If you care about performance, define a function that uses a for
-loop.
function sum(arr) {
var res = 0;
for (var x of arr) {
res += x;
}
return res;
}
Benchmark
I benchmarked a selection of implementations using benchmark.js
(typescript version):
const arr = Array.from({ length: 100 }, () => Math.random());
const reducer = function (p: number, a: number) {
return p + a;
};
const recursion = function (arr: number[], i: number) {
if(i > 0) return arr[i] + recursion(arr, i - 1)
else return 0
};
const recursion2 = function (arr: number[], i: number, len: number) {
if(i < len) return arr[i] + recursion2(arr, i + 1, len)
else return 0
};
const recursion3 = function (arr: number[], i: number) {
if(i < arr.length) return arr[i] + recursion3(arr, i + 1)
else return 0
};
new Benchmark.Suite()
.add("jquery", () => {
let res = 0;
$.each(arr, (_, x) => (res += x));
})
.add("lodash", ()=>_.sum(arr))
.add("forEach", () => {
let res = 0;
arr.forEach((x) => (res += x));
})
.add("reduce", () => arr.reduce((p, a) => p + a, 0))
.add("predefined reduce", () => arr.reduce(reducer, 0))
.add("eval", () => eval(arr.join("+")))
.add("recursion", () => recursion(arr, arr.length - 1))
.add("recursion2", () => recursion2(arr, 0, arr.length))
.add("recursion3", () => recursion3(arr, 0))
.add("naive", () => (
arr[0]+arr[1]+arr[2]+arr[3]+arr[4]+arr[5]+arr[6]+arr[7]+arr[8]+arr[9]+
arr[10]+arr[11]+arr[12]+arr[13]+arr[14]+arr[15]+arr[16]+arr[17]+arr[18]+arr[19]+
arr[20]+arr[21]+arr[22]+arr[23]+arr[24]+arr[25]+arr[26]+arr[27]+arr[28]+arr[29]+
arr[30]+arr[31]+arr[32]+arr[33]+arr[34]+arr[35]+arr[36]+arr[37]+arr[38]+arr[39]+
arr[40]+arr[41]+arr[42]+arr[43]+arr[44]+arr[45]+arr[46]+arr[47]+arr[48]+arr[49]+
arr[50]+arr[51]+arr[52]+arr[53]+arr[54]+arr[55]+arr[56]+arr[57]+arr[58]+arr[59]+
arr[60]+arr[61]+arr[62]+arr[63]+arr[64]+arr[65]+arr[66]+arr[67]+arr[68]+arr[69]+
arr[70]+arr[71]+arr[72]+arr[73]+arr[74]+arr[75]+arr[76]+arr[77]+arr[78]+arr[79]+
arr[80]+arr[81]+arr[82]+arr[83]+arr[84]+arr[85]+arr[86]+arr[87]+arr[88]+arr[89]+
arr[90]+arr[91]+arr[92]+arr[93]+arr[94]+arr[95]+arr[96]+arr[97]+arr[98]+arr[99]))
.add("loop with iterator", () => {
let res = 0;
for (const x of arr) res += x;
})
.add("traditional for loop", () => {
let res = 0;
// cache the length in case the browser can't do it automatically
const len = arr.length;
for (let i = 0; i < len; i++) res += arr[i];
})
.add("while loop", () => {
let res = 0;
let i = arr.length;
while (i--) res += arr[i];
})
.add("loop in a function ", () => sum(arr))
.on("cycle", (event) => console.log(String(event.target)))
.run();
In chrome 104, the for
-loop-based implementations are the fastest:
jquery x 1,832,472 ops/sec ±1.35% (61 runs sampled)
lodash x 2,079,009 ops/sec ±1.11% (68 runs sampled)
forEach x 4,887,484 ops/sec ±2.35% (67 runs sampled)
reduce x 21,762,391 ops/sec ±0.46% (69 runs sampled)
predefined reduce x 2,026,411 ops/sec ±0.50% (68 runs sampled)
eval x 33,381 ops/sec ±2.54% (66 runs sampled)
recursion x 2,252,353 ops/sec ±2.13% (62 runs sampled)
recursion2 x 2,301,516 ops/sec ±1.15% (65 runs sampled)
recursion3 x 2,395,563 ops/sec ±1.65% (66 runs sampled)
naive x 31,244,240 ops/sec ±0.76% (66 runs sampled)
loop with iterator x 29,554,762 ops/sec ±1.07% (66 runs sampled)
traditional for loop x 30,052,685 ops/sec ±0.67% (66 runs sampled)
while loop x 18,624,045 ops/sec ±0.17% (69 runs sampled)
loop in a function x 29,437,954 ops/sec ±0.54% (66 runs sampled)
Firefox 104 shows similar behaviour:
jquery x 1,461,578 ops/sec ±1.58% (64 runs sampled)
lodash x 4,931,619 ops/sec ±0.80% (66 runs sampled)
forEach x 5,594,013 ops/sec ±0.51% (68 runs sampled)
reduce x 3,731,232 ops/sec ±0.53% (66 runs sampled)
predefined reduce x 2,633,652 ops/sec ±0.54% (66 runs sampled)
eval x 105,003 ops/sec ±0.88% (66 runs sampled)
recursion x 1,194,551 ops/sec ±0.24% (67 runs sampled)
recursion2 x 1,186,138 ops/sec ±0.20% (68 runs sampled)
recursion3 x 1,191,921 ops/sec ±0.24% (68 runs sampled)
naive x 21,610,416 ops/sec ±0.66% (66 runs sampled)
loop with iterator x 15,311,298 ops/sec ±0.43% (67 runs sampled)
traditional for loop x 15,406,772 ops/sec ±0.59% (67 runs sampled)
while loop x 11,513,234 ops/sec ±0.60% (67 runs sampled)
loop in a function x 15,417,944 ops/sec ±0.32% (68 runs sampled)
Discussion
Implementations defining an anonymous function are generally slower because creating an anonymous function is a significant overhead. When running the benchmark with a large array, e.g., with length 1000 instead of 100, the difference between reduce
and the for
-loop-based implementations becomes insignificant in chrome.
Chrome’s V8 engine knows how to inline simple anonymous functions in reduce
since the reduce
test case is much faster than the predefined reduce
test case. Firefox seems to try something similar but is less efficient in doing so. Non-inlined function calls are pretty slow in js since the call stack is less efficient than the call stack in compiled software.
Similar to reduce
, the forEach
– and jquery
-based implementations use anonymous functions and are relatively slow. lodash
has a specialized sum
implementation, but it is (as of v4.0.0) implemented as a special case of sumBy
, which is relatively inefficient.
eval
is the by far slowest test case. This makes sense since constructing the string using concatenations might cause several dynamic allocations (which are slow). Next, the parser has to be invoked and only then can the code be finally executed.
I’ve included some recursive implementations because some people on the internet claim that recursion is faster than loops in js. I can’t reproduce their example – using benchmark.js
, recursion is very slow, and when using console.time
with a loop, both functions take the same time. When calculating the sum, as expected, recursion is much slower than loops, probably due to intense usage of the js call stack.
The naive implementation would be manually adding all 100 elements of the array. While being quite inconvenient, this is the fastest implementation. But, luckily, for
-loops come very close. Adding a single function call around the loop doesn’t harm the performance. Therefore, you can feel free to use the utility function from above.
I have no explanation why the while
loop is slower than the for
loop. Iterating the array in reverse doesn’t seem to be the problem here.
Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article
In this article, we will learn how we can find the sum of all elements/numbers of the given array. There are many approaches to solving the problems using for loop, forEach() method, and reduce() method.
Below all the approaches are described with a proper example:
JavaScript for loop: We are simply going to iterate over all the elements of the array using a Javascript for loop to find the sum.
Example:
Javascript
<script>
var
arr = [4, 8, 7, 13, 12]
var
sum = 0;
for
(let i = 0; i < arr.length; i++) {
sum += arr[i];
}
console.log(
"Sum is "
+ sum)
</script>
Output:
Sum is 44
JavaScript forEach() Method: We are going to use the Javascript forEach() method of the array to calculate the sum.
Javascript
<script>
var
arr = [4, 8, 7, 13, 12]
var
sum = 0;
arr.forEach(x => {
sum += x;
});
console.log(
"Sum is "
+ sum);
</script>
Output:
Sum is 44
JavaScript reduce() Method: We are going to use the Javascript reduce() method to find the sum of the array.
Example:
Javascript
<script>
var
arr = [4, 8, 7, 13, 12]
var
sum = arr.reduce(
function
(x, y) {
return
x + y;
}, 0);
console.log(
"Sum using Reduce method: "
+ sum);
</script>
Output:
Sum using Reduce method: 44
Using Recursion:
Javascript
var
arr = [4, 8, 7, 13, 12];
function
sumArray(arr, index) {
if
(index === arr.length) {
return
0;
}
return
arr[index] + sumArray(arr, index + 1);
}
console.log(
"Sum is "
+ sumArray(arr, 0));
Time Complexity: O(n)
Auxiliary Space: O(1)
Last Updated :
25 Jan, 2023
Like Article
Save Article
Сложение чисел массива методом reduce()
massiv.reduce((a,b)=>a+b) или massiv.reduce((a,b)=>b+a)
Мы передаём первым параметром функцию, которая возвращает нам результат сложения предыдущего значения со следующим. При первом вызове предыдущим будет первый элемент массива, а следующим — второй элемент. После первого вызова новый массив уменьшается на один первый элемент. В новом массиве первым элементом становится результат предыдущего вызова коллбэка.
Решение для массива из чисел методом map()
massiv.map(i=>x+=i, x=0).reverse()[0]
massiv — это тот массив, на котором мы вызываем методы. То есть тот массив, в котором нужно сложить все числа.
Мы используем второй аргумент функции map(), чтобы создать переменную «над» функцией обратного вызова (над первым аргументом map()). Коллбек будет видеть нашу переменную «x» как внешнюю (объявленную до коллбека), а значит возврат «x+=i» постоянно будет пополнять значение переменной «x».
В это время map() будет вышагивать по элементам оригинального массива и обновлять значение переменной «x». На каждой итерации он будет возвращать текущее значение переменной «x» в новый массив. Когда map() дойдёт до конца, тогда последний элемент нового массива будет хранить в себе сумму всех элементов оригинального массива.
Для простоты доступа к сумме значений мы перевернём новый массив методом reverse(). Последний элемент станет первым. Нам останется только обратиться к первому элементу нового массива. И всё. Готово!
…дополнение
Про второй параметр. Про «x=0». Работа JavaScript управляется ГЛОБАЛЬНЫМ объектом. В среде выполнения кода, которая находится в браузере, этим ГЛОБАЛЬНЫМ объектом является объект Window. Из консоли браузера к нему можно обратиться при помощи команды «window».
Так вот когда мы пишем «x=0», в этот момент мы создаём у объекта Window новое свойство, ключом которого является «x», а значением «0».
Если посмотреть на это со стороны, то по сути у нас всегда есть какой-то контейнер для хранения нужных нам данных — это объект Window. И в некоторых случаях нам не обязательно использовать var, let или const для создания отдельных переменных (но есть нюансы!)
Тема с «x=0» осталась не раскрытой. Не все уловили этот момент присваивания.
Пример работы — скопируй и вставь в консоль браузера — потестируй!
var massiv = [1,,-1,,111,,2,,-2] massiv.map(i=>x+=i, x=0).reverse()[0] 111
Видео работы через map()
Функция с методом map()
function summArrayElements(arr){ let x = 0; return arr.map(i=>x+=i, x).reverse()[0] }
Стабильный способ для массива из чисел
Если элементами массива являются ТОЛЬКО числа, то можно написать функцию и использовать цикл for:
function sum (x){ var s = 0; for (i = 0; i < x.length; i++){ s += x[i] } return s }
В эту функцию мы будем передавать один аргумент, который будет являться массивом.
Пробуем передать массив [1, 10, 100, 1000] в функцию.
Мы получили ожидаемый результат.
sum([1, 10, 100, 1000]) 1111 // результат выполнения функции
Функция хорошо отработала на одном типе данных.
Собственный метод для экземпляров Array
Ещё можно расширить набор методов для прототипов Array:
Array.prototype.sum = function(){ var s = 0; for (i = 0; i < this.length; i++){ s += this[i] } return s }
Таким образом мы сможем вызывать наш собственный метод на любом массиве. Но нужно понимать, что в таком виде функция хорошо отрабатывает только тип данных — Number.
[-1, -10, 1, 10, 111].sum() 111 // результат сложения значений элементов массива
[2, 4, 6, 8, 10].sum() 30 // результат суммирования значений элементов массива
Если в такую функцию передать числа и строки, то получится плохой результат:
[2, 4, "efim360.ru", 8, 10].sum()
Первые два числа в массиве сложатся и мы увидим 6, но как только появится строка, то оператор «+» начнёт конкатенировать все остальные элементы и превращать их в строковые значения. То есть символы начнут слипаться в одну строку. В этом случае результат НЕ будет числом, а это ошибка. Нужно дорабатывать алгоритм и ставить проверку типа данных.
Улучшение № 1 — попытка приведения строки к числу
Может оказаться так, что внутри массива будут строки, которые по факту хранят в себе только цифры и знак минус — (символизирует отрицательное число)
[2, 4, "6", 8, 10, "-10"]
В этом случае нужно попытаться привести строку к числу, а потом сравнить является ли приведённое значение типом Number. Функция будет доработана.
Array.prototype.sum = function(){ var s = 0; for (i = 0; i < this.length; i++){ s += Number(this[i]) } return s }
Результат работы:
Альтернатива (нерабочее условие — можно не читать)
Array.prototype.sum = function(){ var s = 0; for (i = 0; i < this.length; i++){ if ( Number(this[i]) == NaN) {continue} // это условие бесполезно, читай ниже "почему?". else { s += Number(this[i]) } } return s }
Результат работы:
Улучшение № 2 — отбрасывание элементов, которые нельзя привести к числу
Среди строк может оказаться такая, которую нельзя будет привести к числу. Их нужно пропускать.
[2, 4, "6", 8, "JavaScript", 10, "-10"]
Допишем нашу функцию
Array.prototype.sum = function(){ var s = 0; for (i = 0; i < this.length; i++){ if ( isNaN(this[i]) == true) {continue} else { s += Number(this[i]) } } return s }
Пример работы:
У Глобального Объекта (Global Object) JavaScript есть свои функциональные свойства:
- eval ( x )
- isFinite ( number )
- isNaN ( number )
- parseFloat ( string )
- parseInt ( string, radix )
- Функции обработки URI
Функция isNaN ( number ) — это внутренний объект %isNaN%. Когда функция isNaN вызывается с одним аргументом number, выполняются следующие шаги:
1. Пусть num будет ? ToNumber(number). 2. Если num является NaN, вернуть true. 3. В противном случае вернуть false.
«This is Not a Number?» — расшифровка названия функции. На русском будет звучать так: «Это является Не Числом?«. Под «this/это» подразумевается то, что мы передаём в функцию.
То есть когда мы передадим в функцию isNaN() строку с буквами или прочими символами, тогда абстрактная операция ToNumber (перевод строки в число) вернёт нам NaN — и если это так, то функция isNaN() вернёт true. Условно можно сказать, что попытка отбросить кавычки не сделала из строки число.
Ещё важно учитывать, что один NaN всегда НЕ равен другому NaN, потому что по сути под любым NaN скрывается какое-то уникальное значение с типом данных Number.
Информационные ссылки
JavaScript | Массивы (Array)
Официальная страница стандарта ECMAScript — Раздел «22.1 Array Objects» — https://tc39.es/ecma262/#sec-array-objects
Официальная страница стандарта ECMAScript — https://tc39.es/ecma262/
Свойства конструктора Array
Свойства объекта прототипа Array
JavaScript | Как сложить все положительные числа в массиве?
JavaScript | Как сложить все отрицательные числа в массиве?
JavaScript | How do I add all the numbers in an array?
In this shot, we will discuss three methods you can use to get the total of a given array in JavaScript.
First, we’ll use the traditional for
loop. Secondly, we’ll use forEach
, an array-like method, and lastly, we’ll make use of for...of
.
In this shot, our array example is [1, 4, 0, 9, -3]
, and the expected output is 11
.
1. Using the traditional for
loop
In this method, you iterate and add each item until you reach the last item.
function sumArray(array){
let sum = 0 // the sum is initialed to 0
/* js arrays are zero-index based
ourArray.length = 5, the initialization block is set to 0.
the last item is index 4 that is < 5 (what we define in the condition block)
*/
for (let i = 0; i <
array.length; i += 1) {
// take every item in the array and add it to sum variable
sum += array[i]
// initial: sum = 0
// iteration 1: 0 + 1 => sum = 1
// iteration 2: 1 + 4 => sum = 5
// iteration 3: 5 + 0 => sum = 5
// iteration 4: 5 + 9 => sum = 14
// iteration 5: 14 + -3 => sum = 11
}
console.log(sum) // 11
// return sum
return sum
}
// call the function and give it our array
sumArray([1, 4, 0, 9, -3]); // logs 11
Code without comments
В этом посте мы обсудим, как найти сумму всех значений массива в JavaScript.
1. Использование Array.prototype.reduce()
функция
The reduce() можно использовать для выполнения функции редуктора для каждого элемента массива. Чтобы вычислить сумму всех значений массива, функция редуктора должна добавить текущее значение элемента к уже вычисленной сумме предыдущих значений.
Подводя итог, значения, содержащиеся в массиве, вы должны указать значение по умолчанию для reduce()
метод, иначе код выдаст TypeError
на пустой массив. Это показано ниже с использованием анонимной функции.
add = function(arr) { return arr.reduce((a, b) => a + b, 0); }; var arr = [3, 6, 1, 5, 8]; var sum = add(arr); console.log(sum) /* результат: 23 */ |
Скачать Выполнить код
В ES6 у нас есть стрелочные функции, которые упрощают приведенный выше синтаксис.
const add = arr => arr.reduce((a, b) => a + b, 0); var arr = [3, 6, 1, 5, 8]; var sum = add(arr); console.log(sum) /* результат: 23 */ |
Скачать Выполнить код
2. Использование библиотеки Lodash
В библиотеке Lodash есть _.sum метод, который может вычислить сумму значений в массиве.
var _ = require(‘lodash’); var arr = [3, 6, 1, 5, 8]; var sum = _.sum(arr); console.log(sum) /* результат: 23 */ |
Скачать код
Вот и все, что нужно для нахождения суммы всех значений массива в JavaScript.
Спасибо за чтение.
Пожалуйста, используйте наш онлайн-компилятор размещать код в комментариях, используя C, C++, Java, Python, JavaScript, C#, PHP и многие другие популярные языки программирования.
Как мы? Порекомендуйте нас своим друзьям и помогите нам расти. Удачного кодирования 🙂