合計
コードはこちらです。
/**
* 配列の合計を求める関数
* @param {number[]} array
* @returns {number} 合計
*/
function sum(array) {
return array.reduce((acc, cur) => acc + cur, 0)
}
sum([3, 6]) // 9
sum([1, 3, 5, 2]) // 11
このコードでは、配列のreduce
メソッドを用いて合計を計算しています。
reduce
とは
配列のreduce
は、配列の要素を縮小するメソッドです。
縮小には指定したコールバック関数が使われます。
コールバックは各要素ごとに順番に実行され、返した値が次のループに使われます。
以下の引数で呼び出されます。
-
accumulator
: 前回のコールバック関数が返した値 -
currentValue
: 現在のループの要素 -
currentIndex
: 現在のループのインデックス -
array
: 呼び出されている配列そのもの
例えば、コールバック関数でaccmulator
とcurrentValue
を足し、それを返すようにします。
すると簡単に配列の合計が計算できます。
const array = [1, 3, 5]
const sum = array.reduce((acc, cur) => {
return acc + cur // 合計を返す
})
sum // 9
初期値
コールバック関数が一番最初に呼び出されるとき、accmulator
は配列の一番最初の要素になります。
そのためcurrentValue
は配列の1
番目(0
ではない)の要素が最初に入ります。
const array = [1, 3, 5]
array.reduce((acc, cur) => { // 1と3が最初に入る
return acc + cur
})
そして、呼び出された配列の中身が空([]
)だった場合、reduce
はエラーを投げます。
const array = []
array.reduce((acc, cur) => acc + cur) // Error!
今回のsum
関数は配列が[]
でもエラーではなく0
を返したいので、これは問題です。
そこで、第二引数のinitialValue
が使えます。
これはaccmulator
の初期値を設定するもので、これを入れると配列が[]
でもエラーを投げなくなります。
今回は初期値に数値の0
を設定します。
const array = []
array.reduce((acc, cur) => acc + cur, 0) // 0
もちろん、array.length
をチェックするなどして配列が空であることを確認してもOKです。
function sum(array) {
if (array.length <= 0) return 0
return array.reduce((acc, cur) => acc + cur)
}
個人的には初期値を設定したほうがすっきりするので好きです。
function sum(array) {
return array.reduce((acc, cur) => acc + cur, 0)
}
for...of
の場合
先ほどのコードは、以下のようにfor...of
文で書くこともできます。
function sum(array) {
let result = 0
for (const num of array) {
result += num
}
return result
}
sum([3, 6]) // 9
sum([1, 3, 5, 2]) // 11
このコードでは合計をresult
変数で管理し、配列の要素を順番に足していっています。
そして計算し終わったらresult
を返しています。
平均
コードはこちらです。
/**
* 配列の平均を求める関数
* @param {number[]} array
* @returns {number} 平均
*/
function average(array) {
const sum = array.reduce((acc, cur) => acc + cur, 0)
return sum / array.length
}
average([3, 5]) // 4
average([5, 8, 10, 2, 16]) // 8.2
求め方
平均は以下の手順で求められます。
- 合計(
sum
)を計算する -
sum
を要素数(array.length
)で割る
average
関数は、先ほどと同じ方法で合計を計算し、それをarray.length
で割ったものを返しています。
中央値
コードはこちらです。
/**
* 配列の中央値を求める関数
* @param {number[]} array
* @returns {number} 中央値
*/
function median(array: number[]) {
const sorted = array.toSorted((a, b) => a - b)
const centerIndex = sorted.length / 2
// 真ん中のインデックスが小数か? = array.lengthが奇数か?
if (Number.isInteger(centerIndex)) {
// 偶数 中央に近い2つの数の平均を返す
const a = sorted[centerIndex - 1]
const b = sorted[centerIndex]
return (a + b) / 2
} else {
// 奇数: インデックスを切り捨てて返す
return sorted[Math.floor(centerIndex)]
};
}
求め方
中央値は以下の手順で求めることができます。
- 配列の要素をソートする(
sorted
) - 真ん中のインデックス(
sorted.length
)が小数かを判定する - 小数の場合: 切り捨てた位置にある値を返す
- 整数の場合: 真ん中に近い2つの値の平均を返す
配列の要素をソートする
ソートには配列のtoSorted
メソッドを使います。
このメソッドはsort
に似ていて、ソートした新しい配列を返します。
array.toSorted((a, b) => a - b)
引数に入れた関数(compareFn
)は、どのようにソートするかを示すものです。
ここでのa - b
は数値を昇順でソートします。
なお、ここではcompareFn
の戻り値が何を示すのかわからなくても大丈夫です。
中央値を求めるにあたって、ソートが昇順でも降順でも結果は変わりません。
toSorted
の詳細はMDNをご覧ください。
真ん中のインデックスが小数か判定する
まず、以下のコードでは、この後何度も出てくる真ん中のインデックスに名前をつけています。
これは単純にsorted.length
を2
で割ったものです。
const centerIndex = sorted.length / 2
centerIndex
の値は以下のようになります。
-
sorted.length
が偶数の場合: 整数 -
sorted.length
が奇数の場合:~.5
という形の小数
また、中央値は数値の数が偶数か奇数かで少し求め方が変わります。
- 偶数の場合: 真ん中に最も近い2つの数の平均になる
- 奇数の場合: 真ん中の数になる
このため、currentIndex
が小数かどうかを判定し、そこから条件分岐で処理を変える必要があります。
判定方法
数が整数かどうか判定するには、Number.isInteger
メソッドが使えます。
if (Number.isInteger(centerIndex) {
// 整数の場合
} else {
// 小数の場合
};
整数の場合
整数の場合=配列の長さが偶数の場合、以下の値を返します。
- 中央に近い小さいほうのインデックス(
currentIndex - 1
)の値を取得する - 中央に近い大きいほうのインデックス(
currentIndex
)の値を取得する - 1と2の値の平均を返す
コードだとこの部分になります。
const a = sorted[centerIndex - 1]
const b = sorted[centerIndex]
return (a + b) / 2
小数の場合
小数の場合、以下の値を返します。
-
centerIndex
を切り捨てる - 1のインデックスの値を返す
コードだとこの部分になります。
return sorted[Math.floor(centerIndex)]
ここで切り捨てている(Math.floor
を使っている)理由は、配列のインデックスが0
から始まるからです。
例えば、インデックス0 ~ 2
の中央は、3 / 2 = 1.5
を切り捨てて1
になります。