Hike News
Hike News

reduce() 陣列累加

關於 reduce()

利用 reduce() 可以將陣列的值依序從第一個值到最後一個值套用到函式運算,使得原本使用 For 迴圈的累計更加簡潔,再加上箭頭函式一起使用就可以更簡化易讀。

在不知道 ruduce() 之前,對於陣列的值要作 2 個、2 個的加減或是判斷,就會想到用 for 迴圈先取得一個值再向後得到第 2 個值後再作運算,若是要作出排序、比較的話要再用 if 判斷回傳結果,使用 for 迴圈就會變得複雜多了。

在陣列內的值並不會限定必需是數字 reduce() 才能用,值是字串也是可以的;若是將包含了數字和字串的陣列作加減時,還需要注意結果是 數值 或是 字串

For 迴圈

用陣列內的值 1 個 1 個累加得到的值為例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 數字累加
let array = [1, -1, 20, 5];
let sum = 0;
for(let n of array) {
sum += n;
}
console.log(sum); // 25

// 字串累加
let array = ['1', '-1', '20', '5'];
let sum = 0;
for(let n of array) {
sum += n;
}
console.log(sum); // "01-1205"

// 數字和字串混用
let array = [1, '-1', 20, '5'];
let sum = 0;
for(let n of array) {
sum += n;
}
console.log(sum); // "1-1205"

字串累加的結果是因為 sum 一開始的值是 0 ,所以累加時作為 數值 和 字串 相加才得出 01-125

在數字和字串相加的時侯會因為遇到字串轉為字串相加,以數字和字串混用的例子,一開始的值 0 是數字所以和陣列的第一個值 1 作數字相加得到 1,而第二個值是字串所以從這之後的累加就會全是字串相加的結果。

雖然和 reduce() 得到的結果是相同的,但不同的是 reduce() 有多一個 繼承前次結果 的值提供給下一次運算使用,也是因為多了這個繼承的結果,所以可以產生更多的應用,這裡還是先用 for 迴圈做 reduce() 的運算方式

1
2
3
4
5
6
7
8
9
10
11
let array = [1, -1, 20, 5];
let sum = 0;
let total = '';
for(let i = 0; i < (array.length - 1); i++) {
if (i == 0 ) {
sum = array[i] + array[i + 1]
} else {
sum += array[i + 1]
}
}
console.log(sum); // 25

若是作排序

1
2
3
4
5
6
7
8
9
10
11
12
13
let array = [1, -1, 20, 5];
let sum = 0;
let ary = []; // 作為暫存用
for(let i = 0; i < (array.length - 1); i++) {
for(let j = 0; j < array.length - i - 1; j++){
if(array[j]>array[j+1]){
ary = array[j];
array[j] = array[j+1];
array[j+1] = ary;
}
}
}
console.log(array); // [-1, 1, 5, 20]

雖為也是作的到,但使用的行數有點多,所以可以改用 reduce() 會更為簡單。

reduce()、reduceRight()

MDN 對 Array.prototype.reduce() 的解釋

方法是將一個累加器及陣列中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。

得知 reduce() 在使用時必需配合一個會回傳的函式使用,並且在最後回傳一個值。

reduce() 是取陣列由左至右的值,而要相反取值時可以用 reduceRight() 由右至左取值。


在使用 reduce() 時若是沒有函式回傳值作為 繼承的值 ,他會什麼結果也不會回傳給你,就像

陣列.reduce((繼承前次累加的結果, 陣列依順序取得值) => 回傳結果)

如果在前次的結果沒回傳也就是連 0 或 “” 都不是的情形,執行第 2 次和之後的運算所繼承的就會是 undefined

由下方的例子來看,就可以更清楚了

1
2
3
4
5
6
7
8
let ary = [1, -1, 20, 5];
ary.reduce();
// undefined is not a function

ary.reduce((a, b) => console.log(a, b));
// 1 -1
// undefined 20
// undefined 5

這一個作為 繼承的值reduce() 內的函式內就等於是 ( 繼承前次的結果, 陣列依順序取得值) => 回傳結果 ,而直到結束時回傳為 reduce() 的結果。


1
ary.reducer(accumulator, currentValue)

到目前使用到的 2 個參數為 accumulator 繼承前次的結果 、currentValue 陣列依順序取得值

參數另外還有作為陣列的索引 currentIndex 、 呼叫完整的陣列 array 、 initialValue 初始值可用

1
2
3
4
5
6
7
8
9
ary.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)

// 完整函式
ary.reduce( function (accumulator, currentValue, currentIndex, array) {
return accumulator + currentValue;
}, initialValue
);
// 箭頭函式
ary.reduce((accumulator, currentValue, currentIndex, array) => accumulator + currentValue, initialValue);

使用前面的陣列作累加為例

1
2
let ary = [1, -1, 20, 5];
console.log(ary.reduce((accumulator,currentValue) => accumulator + currentValue)) // 25

這和用 For 迴圈得到的值是相同的,同樣是累加,用 reduce() 加上箭頭函式就讓整個程式碼更簡潔了。


參數 initialValue 是作為初始的值

1
2
let ary = [1, -1, 20, 5];
console.log(ary.reduce((accumulator, currentValue) => accumulator + currentValue, 0)) // 25

數字累加的情況下還看不出什麼,但換成字串時

1
2
let ary = ['1', '-1', '20', '5'];
console.log(ary.reduce((accumulator, currentValue) => accumulator + currentValue, 0)) // "01-1205"

就會發現得到的值是 “01-1205”,為什麼呢 ? 這是因為 accumulator 在初始時會先取得初始值 initialValue ,若是 initialValue 沒有值就會以索引 0 為初始值並從索引 1 開始。

而這個例子是因為 initialValue 是數字,和字串相加時自然的 0 就會轉成字串和陣列內的值相加。

要知道取得的值是在陣列的什麼位置,可以加上 currentIndex 參數,並在函式內加上 console.log(currentIndex); 借此來觀察發現索引是從 0 還是 1 開始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let ary = ['1', '-1', '20', '5'];
console.log(ary.reduce(function (accumulator, currentValue, currentIndex ) {
console.log(currentIndex);
return accumulator + currentValue
})) // "1-1205"
// 1
// 2
// 3
// "1-1205"


let ary = ['1', '-1', '20', '5'];
console.log(ary.reduce(function (accumulator, currentValue, currentIndex ) {
console.log(currentIndex);
return accumulator + currentValue
}, 0))
// 0
// 1
// 2
// 3
// "01-1205"

預設 initialValue = 0 可以省略不寫。

也可以是字串和陣列相加

1
2
3
4
let ary = [1, -1, 20, 5];
console.log(ary.reduce(function (accumulator,currentValue, currentIndex ) {
return accumulator + currentValue
}, '結果 = ')) // "結果 = 1-1205"

參考

Array.prototype.reduce()
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Array.prototype.reduceRight()
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight