此系列筆記主要依照 [Udemy] Learning Algorithms in JavaScript from Scratch by Eric Traub 的課程脈絡加以整理,但部分程式碼是消化後以自己較易理解的方式重新撰寫,因此和原課程內容有些出入。
問題描述
當我們傳入一個全都是數值的陣列時,計算這些數值的 加總/總合(sum)、平均數(mean)、中位數(Median)和眾數(Mode),並以物件的方式回傳:
function meanMedianMode (arr) {
// call other three function
// return obj which has mean, median, mode in it
}
function getMean (arr) {...}
function getMedian (arr) {...}
function getMode (arr) {...}
演算法實做
平均數(Mean)
計算平均數之前,我們要先把所有數字加總,加總的方式我們可以使用 Array.prototype.reduce 這個方法:
let sum = arr.reduce((acc, cur) => acc + cur)
接著在除以所有的陣列數目 sum / arr.length ,最後我們可以透過 Math.round() 將輸出的結果進行四捨五入:
function getMean (arr) {
let sum = arr.reduce((acc, cur) => acc + cur)
let mean = sum / arr.length
return Math.round(mean * 100) / 100 // 取到小數第二位
}
中位數(Median)
中位數會有兩種情況,當輸入陣列的個數是奇數時,就取最中間的那個;當輸入的數目是偶數時,則要取最中間的那兩個加總除以二。
當數目是偶數時中數會是:
median = (arr[arr.length / 2] + arr[arr.length / 2 - 1]) / 2
這裡要注意的是,因為陣列裡面是使用 index,所以是 arr.length / 2 - 1 而不是 +1 。
當數目是奇數時,中數會是:
median = arr[(arr.length - 1) / 2 ]
綜合起來:
function getMedian (arr) {
arr = arr.sort((a, b) => a - b)
let median
if (arr.length % 2 === 0) {
// 數目為偶數
median = (arr[arr.length / 2] + arr[arr.length / 2 - 1]) / 2
} else {
// 數目為奇數
median = arr[(arr.length - 1) / 2 ]
}
return median
}
眾數(mode)
最後一個稍稍複雜的是計算眾數,這裡我們會用到在先前 Harmless Ransom Note 計算陣列中每個元素出現幾次的方法。
我們先計算在陣列中每一個元素出現幾次:
function getMode (arr) {
let countList = {}
for (let value of arr) {
// 將陣列中的 Number 當作 String 來處理,以計算出現次數
value = value.toString()
if (!countList[value]) countList[value] = 0
countList[value]++
}
/* ... */
}
接著我們要根據這個 countList 找出被計數最多的元素:
function getMode (arr) {
/* ... */
let maxCount = 0
let mode = [] // 眾數
for (let prop in countList) {
if (maxCount < countList[prop]) {
maxCount = countList[prop]
mode = [prop]
} else if (maxCount === countList[prop]) {
// 如果有同樣數目的眾數
mode.push(prop)
}
}
// 如果每個元素的計數一樣,則沒有眾數
if (mode.length === Object.keys(countList).length) {
mode = []
}
return mode
}
meanMedianMode
最後我們多一個小小的判斷,如果輸入的數值包含不是數值的話,則給予警告:
function meanMedianMode (arr) {
arr.forEach(item => {
if (!(/^[0-9]+$/.test(item))) {
console.warn(item + ' is not a number.')
}
})
return {
mean: getMean(arr),
median: getMedian(arr),
mode: getMode(arr)
}
}
完整程式碼
function meanMedianMode (arr) {
arr.forEach(item => {
if (!(/^[0-9]+$/.test(item))) {
console.warn(item + ' is not a number.')
}
})
return {
mean: getMean(arr),
median: getMedian(arr),
mode: getMode(arr)
}
}
/**
* 計算加總與平均數
**/
function getMean (arr) {
let sum = arr.reduce((acc, cur) => acc + cur)
let mean = sum / arr.length
return Math.round(mean * 100) / 100 // 取到小數第二位
}
/**
* 計算中位數
**/
function getMedian (arr) {
arr = arr.sort((a, b) => a - b)
let median
if (arr.length % 2 === 0) {
// 數目為偶數
median = (arr[arr.length / 2] + arr[arr.length / 2 - 1]) / 2
} else {
// 數目為奇數
median = arr[(arr.length - 1) / 2 ]
}
return median
}
/**
* 計算眾數
**/
function getMode (arr) {
let countList = {}
for (let value of arr) {
value = value.toString()
if (!countList[value]) countList[value] = 0
countList[value]++
}
let maxCount = 0
let mode = []
for (let prop in countList) {
if (maxCount < countList[prop]) {
maxCount = countList[prop]
mode = [prop]
} else if (maxCount === countList[prop]) {
mode.push(prop)
}
}
if (mode.length === Object.keys(countList).length) {
mode = []
}
return mode
}
console.log(meanMedianMode([1, 2, 3, 4, 5, 4, 6, 1])) // { mean: 3.25, median: 3.5, mode: [ '1', '4' ] }
console.log(meanMedianMode([9, 10, 23, 10 ,23, 9])) // { mean: 14, median: 10, mode: [] }
0 意見:
張貼留言