Cách tìm tổng của một dãy số


808

Cho một mảng [1, 2, 3, 4] , làm thế nào tôi có thể tìm thấy tổng các phần tử của nó? (Trong trường hợp này, tổng sẽ là 10.)

Tôi nghĩ $.eachcó thể hữu ích, nhưng tôi không chắc làm thế nào để thực hiện nó.


4
Câu hỏi này đang được thảo luận về meta
Madara's Ghost

18
@ tereško Không sẵn lòng với google không phải là lý do gần gũi hợp lệ trên Stackoverflow. Vui lòng downvote nếu bạn cảm thấy rằng câu hỏi không được tìm kiếm tốt. (Ngoài ra căn cứ vào câu trả lời - điều này có vẻ là một chủ đề gây nhiều tranh cãi với nhiều giải pháp có thể bao gồm một số thông lệ bỏ phiếu tán rất xấu (eval) -. Ngạc nhiên)
Trilarion

8
Lưu ý: hầu hết các câu trả lời ở đây về cơ bản là tính toán a[0] + a[1] + ..., có thể chuyển thành nối chuỗi nếu mảng có các phần tử không phải là số. Ví dụ ['foo', 42].reduce((a,b)=>a+b, 0) === "0foo42".
Beni Cherniavsky-Paskin

Không có trình giảm tốc nào được tích hợp có thể cung cấp cho Array.reduce? Suy nghĩ một cái gì đó như [1,2,3].reduce(Math.sum).
Phil

Câu trả lời:


544

Khuyến nghị (giảm với giá trị mặc định)

Array.prototype.reduce có thể được sử dụng để lặp qua mảng, thêm giá trị phần tử hiện tại vào tổng của các giá trị phần tử trước đó.

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

Không có giá trị mặc định

Bạn nhận được một TypeError

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

Trước các chức năng mũi tên của ES6

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

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

Đầu vào không số

Nếu không phải là số là đầu vào có thể, bạn có thể muốn xử lý điều đó?

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

Không khuyến cáo sử dụng nguy hiểm

Chúng ta có thể sử dụng eval để thực thi một chuỗi đại diện cho mã JavaScript. Sử dụng hàm Array.prototype.join để chuyển đổi mảng thành chuỗi, chúng tôi thay đổi [1,2,3] thành "1 + 2 + 3", ước tính thành 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('+'))

Tất nhiên hiển thị cảnh báo không phải là điều tồi tệ nhất có thể xảy ra. Lý do duy nhất tôi đưa vào đây là câu trả lời cho câu hỏi của Ortund vì tôi không nghĩ nó đã được làm rõ.


8
Bạn có biết rằng phép thuật reduce()này vẫn chậm hơn 25-30% so với một for()vòng lặp được lập chỉ mục đơn giản sau nhiều năm? jsperf.com/reduce-vs-loop/4
tevemadar

Điều này gặp vấn đề nếu số đó là "0" - nó có thể được hiểu là chuỗi, vì bất kỳ lý do gì. Thêm 1 * a + 1 * b làm việc cho tôi. Về tốc độ, điều này dễ viết hơn và tôi không quan tâm đến tốc độ
Peter Kay

1179

Lisp , đây chính xác là công việc dành cho reduce. Bạn sẽ thấy loại mã này:

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

May mắn thay, trong JavaScript, chúng tôi cũng có reduce! Thật không may, +là một toán tử, không phải là một chức năng. Nhưng chúng ta có thể làm cho nó đẹp! Đây, nhìn kìa:

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

Nó không đẹp sao? :-)

Thậm chí còn tốt hơn! Nếu bạn đang sử dụng ECMAScript 2015 (còn gọi là ECMAScript 6 ), thì nó có thể đẹp như sau:

const sum = [1, 2, 3].reduce((partial_sum, a) => partial_sum + a,0); 
console.log(sum); // 6

28
Giả sử tất cả chúng ta sử dụng ES2015, chúng ta có thể làm cho nó ít dài dòng hơn:[1, 2, 3].reduce((a,b)=>a+b)
Denys Séguret

1
Tôi tự hỏi nếu thời gian thực hiện giảm với một hàm (a, b) có thể so sánh với phép lặp và tổng kết thủ công hoặc nếu có một số chi phí đáng kể bao gồm?
Trilarion

1
Tôi tin rằng điều đáng nói là câu trả lời thực sự có thể được tìm thấy trên trang bạn đã liên kết: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Alex Cohn

2
Tôi sẽ thêm một vài phương thức vào Mảng: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; }
pilat

2
@Black nó giảm một mảng thành một giá trị duy nhất.
Florian Margaine

205

Tại sao không giảm? Nó thường là một chút phản trực quan, nhưng sử dụng nó để tìm một khoản tiền khá đơn giản:

var a = [1,2,3];
var sum = a.reduce(function(a, b) { return a + b; }, 0);

3
IE8 không hỗ trợ nó và có vẻ như jQuery không có ý định thêm nó. Tuy nhiên, Prototype có nó.
Ishmael Smyrnow

4
@Ishmael, bạn có thể sử dụng UnderscoreJS, quay lại triển khai của trình duyệt nếu có hoặc thực hiện theo cách khác.
Pablo Diaz

3
Những gì phản trực giác về reduce()?
canon

3
@ s4nji Array.prototype.reduce() giảm một mảng thành một giá trị trả về duy nhất.
canon

6
@ s4nji ... trừ khi bạn đang giảm nước sốt - trong trường hợp đó, bạn đang bỏ nó xuống các yếu tố cần thiết của nó, tức là tổng của tất cả các hương vị mà không cần nước. :-)
CB Du Rietz

97
var arr = [1,2,3,4];
var total=0;
for(var i in arr) { total += arr[i]; }

3
Đây là cách nhanh hơn giải pháp jQuery.each () ở trên.
Angry Dan

41
@Sprog: Tuy nhiên, sử dụng (var i=0; i<arr.length; i++)thậm chí còn nhanh hơn. Và thậm chí sau đó, sử dụng var sum=0; var i=arr.length; while(i--) sum += arr[i]thậm chí còn nhanh hơn.
Đạp xe

14
Sử dụng for... incác vòng lặp trên mảng hoạt động trong trường hợp này _ trùng hợp ngẫu nhiên_ và vì các mảng mở rộng các đối tượng. Giải pháp của Riking là tốt hơn
Benjamin Gruenbaum

2
@BenjaminGruenbaum cung cấp rằng không có gì có thêm các thuộc tính vô số vào nguyên mẫu của mảng ...
canon

1
@YSC không, không. Một for...invòng lặp trong JavaScript lấy các chỉ số, đó là một vấp ngã phổ biến cho các lập trình viên mong muốn nhận được các giá trị. (Thử for(var i in [1,2,3]) { console.log(i); }trong bảng điều khiển.)
Amber

61
var total = 0;
$.each(arr,function() {
    total += this;
});

87
Xin vui lòng, xin vui lòng sử dụng câu trả lời với reducebên dưới; không khai báo các lọ có thể thay đổi khi bạn không có quá.
Bruno Grieder

9
Câu trả lời này đang được thảo luận về meta
Madara's Ghost

11
Vui lòng không sử dụng điều này, mặc dù đó là "câu trả lời được chấp nhận"; Câu trả lời của Florian dưới đây tốt hơn nhiều!
Andy Sinclair

12
@BrunoGrieder "Không khai báo các vars có thể thay đổi khi bạn không phải" là một ý kiến ​​cực kỳ thiên vị về một ngôn ngữ bắt buộc , nó hầu như không phải là mùi mã bởi bất kỳ sự tưởng tượng nào. Hoàn toàn không có gì sai với câu trả lời của Tyler và sự khác biệt duy nhất giữa Tyler và Florian là phong cách.
Cướp

5
Từ OP: Tôi nghĩ $ .each có thể hữu ích, nhưng tôi không chắc cách triển khai nó. Điều này có thể không phải là tốt nhất, nhưng trả lời yêu cầu của OP.


29

Điều này có thể bằng cách lặp qua tất cả các mục và thêm chúng vào mỗi lần lặp thành một sumbiến đổi.

var array = [1, 2, 3];

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

JavaScript không biết phạm vi khối, vì vậy sumsẽ có thể truy cập được:

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

Giống như trên, tuy nhiên được chú thích và chuẩn bị như một hàm đơn giản:

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

12
Mặc dù thông minh, tôi thấy mã khai báo sumbên ngoài vòng lặp dễ đọc hơn nhiều.
Beni Cherniavsky-Paskin

@ BeniCéciavsky-Paskin Vâng, tương tự ở đây ... Không biết tại sao tôi lại làm theo cách đó ngày hôm đó ... Tuy nhiên, tôi sẽ để nó như vậy! Đó chỉ là một ví dụ về cách chúng ta có thể ... ;)
yckart

Kể từ ES6, javascript DOES biết khối phạm vi với constlet. Vì vậy, bạn có thể khai báo sumbên ngoài forvòng lặp là let sum = 0;. Bạn cũng có thể lưu trữ độ dài mảng trước vòng lặp nhưconst length = array.length;
KSK

23
arr.reduce(function (a, b) {
    return a + b;
});

Tham khảo: Array.prototype.reduce ()


6
Điều này sẽ thất bại nếu arr[].

7
Thêm một giá trị mặc định, như vậy: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];

Điều này sẽ mất trung bình 1,57 ms / lần chạy (được đo trên 1000 lần chạy trên một mảng gồm 100 số bình thường ngẫu nhiên), so với 3,604 ms / lần chạy với eval() phương pháp trên và 2,151 ms / lần chạy với tiêu chuẩn cho (i, length, ++ ) vòng.

Phương pháp lưu ý: thử nghiệm này đã được chạy trên máy chủ Google Apps Script, vì vậy các công cụ javascript của họ khá giống với Chrome.

EDIT: --ithay vìi-- tiết kiệm 0,12 ms mỗi lần chạy (i-- là 1,7)

EDIT: Holy expletive, đừng bận tâm đến toàn bộ bài này. Sử dụng phương thức less () đã đề cập ở trên, nó chỉ 1 ms / lần chạy.


1
Tôi yêu thời gian bạn sử dụng. Câu trả lời của bạn không chỉ nói "Hãy chọn tôi, tôi là tốt nhất!" Nó thay cho chúng ta thấy tại sao . Dù sao, while (--i) do_somethingcó thể làm việc cho những thứ khác quá.
Chương trình Redwolf

var sum = arr[0]
noobninja


12

Bất cứ ai tìm kiếm một oneliner chức năng như tôi? Thực hiện việc này:

sum= arr.reduce(function (a, b) {return a + b;}, 0);

Bạn có thể thêm giá trị ban đầu để giảm làm thông số thứ 2:arr.reduce(function(a, b) { return a + b;}, 0);
Ngz

Cảm ơn! tôi sẽ kết hợp nó
geek-merlin

12

Cách tiếp cận hài hước:

eval([1,2,3].join("+"))

5
Xin vui lòng bạn có thể mở rộng câu trả lời này bằng cách giải thích những gì đang xảy ra trong mã này? Tại sao nó hoạt động? Làm gì chính xác? Những điều này giúp cải thiện chất lượng của câu trả lời.
Ortund

@ user40521 đã trả lời điều này theo cách tôi nghĩ. Tôi đã không nhìn thấy nó.
điện tử

Trong khi điều này là ngắn và ngọt ngào, và chắc chắn thú vị, nó cũng rất không hiệu quả. Sử dụng reducechắc chắn là tốt hơn cho đa số, nếu không phải tất cả, trường hợp.
Ninjakannon

Errm,[1,"2;YourProgram.ripToShreds();3",4]
Chương trình Redwolf

Vì vậy, tôi nhận được NaNkhi thử eval(['alert("removing your computer")',2,3].join("+"))trả lời sai 0/10
pie6k

12

OK, hãy tưởng tượng bạn có mảng này bên dưới:

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

Hãy bắt đầu xem xét nhiều cách khác nhau để làm điều đó vì tôi không thể tìm thấy bất kỳ câu trả lời toàn diện nào ở đây:

1) Sử dụng hàm giảm () tích hợp

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

2) Sử dụng cho vòng lặp

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) Sử dụng vòng lặp while

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

4) Sử dụng mảng forEach

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

và gọi nó như thế này:

total(arr); //return 10

Không khuyến khích tạo nguyên mẫu một cái gì đó như thế này cho Mảng ...


10

Một giải pháp JavaScript tiêu chuẩn:

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 */

Điều này làm việc cho tôi (kết quả nên là 5). Tôi hy vọng không có bất lợi tiềm ẩn trong loại giải pháp này.


1
Ngoài ra, bất kỳ lập trình viên C hoặc Java nào cũng có thể hiểu điều này.
Audrius Meskauskas

với mục đích đơn giản là tổng hợp tất cả các giá trị, vòng lặp đơn giản cũ không có đối thủ về thời gian thực hiện
fedeghe

Vấn đề duy nhất là, hơi khó chịu khi bạn có 20 vòng lặp được lồng vào nhau
Chương trình Redwolf

7
var totally = eval(arr.join('+'))

Bằng cách đó bạn có thể đặt tất cả các loại điều kỳ lạ trong mảng.

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

Tôi chỉ nói đùa một nửa.


26
Tôi đang cười một nửa
caub

eval(['alert("removing your computer")',2,3].join("+"))
pie6k

7

Tôi là người mới bắt đầu với JavaScript và mã hóa nói chung, nhưng tôi thấy rằng một cách đơn giản và dễ dàng để tổng hợp các số trong một mảng là như thế này:

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

Về cơ bản, tôi muốn đóng góp điều này vì tôi không thấy nhiều giải pháp không sử dụng các hàm dựng sẵn và phương pháp này rất dễ viết và dễ hiểu.


1
Làm thế nào khác với câu trả lời năm 2012 hoặc câu trả lời năm 2014 này ? Có hai giải pháp bạn chưa từng thấy.
Dan Dascalescu

5

Một đoạn mã JavaScript ngắn sẽ thực hiện công việc này:

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

Một số người đã đề nghị thêm một .sum()phương thức vàoArray.prototype . Điều này thường được coi là thực hành xấu vì vậy tôi không đề nghị bạn làm điều đó.

Nếu bạn vẫn khăng khăng thực hiện thì đây là một cách viết ngắn gọn:

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

sau đó: [1,2].sum(); // 3

Lưu ý rằng hàm được thêm vào nguyên mẫu đang sử dụng hỗn hợp hàm ES5 và ES6 và cú pháp mũi tên. Cái functionđược khai báo để cho phép phương thức lấy thisbối cảnh từ cái Arraymà bạn đang hoạt động. Tôi đã sử dụng =>cho ngắn gọn trong reducecuộc gọi.


5

Sử dụng một forvòng lặp:

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

Hoặc thậm chí là một forEachvòng lặp:

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

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

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

Để đơn giản, sử dụng reduce:

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

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

4

Không cần initial value! Bởi vì nếu không initial valueđược thông qua, phần tử callback functionkhông được gọi trên phần tử đầu tiên của danh sách và phần tử đầu tiên được truyền vào dưới dạng initial value. Tính năng rất c OO l :)

[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

Đây là một giải pháp một lớp trang nhã sử dụng thuật toán ngăn xếp , mặc dù người ta có thể mất một chút thời gian để hiểu được vẻ đẹp của việc triển khai này.

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

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

Về cơ bản, hàm chấp nhận một mảng và kiểm tra xem mảng đó có chứa chính xác một mục hay không. Nếu sai, nó sẽ bật mục cuối cùng ra khỏi ngăn xếp và trả về mảng đã cập nhật.

Cái hay của đoạn trích này là chức năng bao gồm arr[0]kiểm tra để ngăn chặn vòng lặp vô hạn. Khi nó đạt đến mục cuối cùng, nó sẽ trả về toàn bộ số tiền.


4

Bạn có thể kết hợp phương thức less () với biểu thức lambda:

[1, 2, 3, 4].reduce((accumulator, currentValue) => accumulator + currentValue);


3

tôi thấy tất cả các câu trả lời cho giải pháp 'giảm'

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

3

Sự chính xác

Sắp xếp mảng và bắt đầu tổng số dạng số nhỏ nhất (đoạn trích cho thấy sự khác biệt với số không)

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

Đối với mảng số nhiều chiều sử dụng arr.flat(Infinity)


2

Thủ thuật thú vị ở đây, tôi đã có một lựa chọn nit với rất nhiều câu trả lời truyền thống an toàn không lưu vào bộ nhớ cache độ dài của mảng.

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

Nếu không lưu vào bộ nhớ cache độ dài của mảng, trình biên dịch JS cần đi qua mảng với mỗi lần lặp của vòng lặp để tính toán độ dài, trong hầu hết các trường hợp, nó không cần thiết. V8 và rất nhiều trình duyệt hiện đại tối ưu hóa điều này cho chúng tôi, vì vậy nó ít phải quan tâm hơn, nhưng có những thiết bị cũ hơn được hưởng lợi từ bộ nhớ đệm đơn giản này.

Nếu độ dài có thể thay đổi, bộ nhớ đệm có thể gây ra một số tác dụng phụ không mong muốn nếu bạn không biết tại sao bạn lại lưu vào bộ nhớ cache, nhưng đối với chức năng có thể sử dụng lại, mục đích duy nhất là lấy một mảng và cộng các giá trị lại với nhau phù hợp.

Đây là một liên kết CodePen cho hàm ArraySum này. http://codepen.io/brandonbrule/pen/ZGEJyV

Có thể đây là một suy nghĩ lỗi thời đã bị mắc kẹt với tôi, nhưng tôi không thấy bất lợi khi sử dụng nó trong bối cảnh này.


Vấn đề lưu trữ chiều dài là một cá trích đỏ. Công cụ JS sẽ tối ưu hóa điều này cho bạn mà không chớp mắt.

2

Đó là những câu trả lời thực sự tuyệt vời, nhưng chỉ trong trường hợp nếu các số theo thứ tự như trong câu hỏi (1,2,3,4), bạn có thể dễ dàng làm điều đó bằng cách áp dụng công thức (n * (n + 1)) / 2 trong đó n là số cuối cùng


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

Có mã này loại bỏ hệ điều hành của bạn? Hay nó gửi thông tin cá nhân của bạn cho tôi?

2

Cái này dễ hơn nhiều

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

Một ví dụ phương pháp đơn giản:

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]));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.