二維陣列應用題:Borda Count

2020-05-29
JS新手村

對於二維陣列的使用時機還無法快速判斷,紀錄一下解題的脈絡,幫助重整思考。

Borda Count是一種計分方式。維基通道

以維基百科上的範例當作題目:

理解題目:
設定順位第一名得3分,第二名2分,第三名1分,第四名0分
依照順位排序:1:張三 2:王五 3:李四 4:馬六,這樣的票數有51張,以此類推,
最後算出每一位的分數總和。

思維

1. 先想需要的材料:

  • 有票數的陣列
  • 有權重的陣列
  • 有候選人陣列
  • 有候選人依權重排序的陣列
  • 有最後計算總和的陣列
1
2
3
4
5
6
7
const votes = [51, 5, 23 , 21]; //票數
const weights = [3, 2, 1, 0]; //權重
const candidate = [c1, c2, c3, c4]; //候選人
const scoreBoard = [[1, 2, 3, 4], [2, 3, 2, 2], [3, 4, 4, 3], [4, 1, 1, 1]];
// 1:張三 2:王五 3:李四 4:馬六
// 需要一個大陣列包住數組陣列,二維陣列出現了,第一組陣列為權重3的候選人,第二組為權重2...以此類推
let score = [0, 0, 0, 0]; //總分計算,初始值為0,預計會做累加,按候選人順序排列

2. 想要的結果

以候選人1張三(c1)做例子:(想一下突然卡住了)
得分統計要在candidate = [c1, c2, c3, c4]還是score = [0, 0, 0, 0];這裡?
Ermmm…
應該是在score = [0, 0, 0, 0];吧?!candidate = [c1, c2, c3, c4]是多的嗎?先不用他了…
先以pseudocode記流水帳

1
想把score[0] = votes[0] * wights[0] + votes[1] * wieghts[3]...

連第一行都沒打完就發覺不對勁!😐 votesweights沒有一個規律
這要hardcore打完嗎? 開始發現案情不單純…
再重新思考一次…

scoreBoard的陣列放的是候選人編號(1~4),應該根據scoreBoard把權重 * 票數後丟給對應編號,score的表現形式就會變成

1
2
3
4
5
6
7
8
//從第一筆資料做推演
score[scoreBoard[0][0]] = votes[0] * weights[0]; //score[1] = 51 * 3
score[scoreBoard[0][1]] = votes[1] * weights[0]; //socre[2] = 5 * 3
score[scoreBoard[0][2]] = votes[2] * weights[0]; //score[3] = 23 *3
score[scoreBoard[0][3]] = votes[3] * weights[0]; //score[4] = 21 *3
score[scoreBoard[1][0]] = votes[0] * weights[1]; //score[2] = 51 *2
score[scoreBoard[1][1]] = votes[1] * weights[1]; //score[3] = 5 * 2
//行了!

重整前後的思維差異
前:想依照候選人順序做累加,但加總計分的時找不到規律。
後:依照表格由左至右、由上到下計算完該格總分後給對應的候選人編號

3. 將想法實現成code

既然是依據scoreBoard由左至右由上到下做執行,就由他出發。
他是一個二維陣列,要實現查找到scoreBoard[0][0]的值,必須forEach兩次

1
2
3
4
5
6
7
8
const votes = [51, 5, 23 , 21]; //票數
const weights = [3, 2, 1, 0]; //權重
const scoreBoard = [[1, 2, 3, 4], [2, 3, 2, 2], [3, 4, 4, 3], [4, 1, 1, 1]];
let score = [0, 0, 0, 0];

scoreBoard.forEach(boardValue =>
boardValue.foreach(value =>
score[value] = votes[0] * weights[0];)

可是votes[0]weight[0]也不該寫死,
此時把forEach方法的callback三個參數currentValueindexarray考慮進來,
再看一下scoreBoard裡的值,
scoreBoard[0]都是要乘以權重weight[0];
scoreBoard[n][0]要乘以votes[0]
index該用!

1
2
3
4
5
6
7
8
9
10
const votes = [51, 5, 23 , 21]; //票數
const weights = [3, 2, 1, 0]; //權重
const scoreBoard = [[1, 2, 3, 4], [2, 3, 2, 2], [3, 4, 4, 3], [4, 1, 1, 1]];
let score = [0, 0, 0, 0];

scoreBoard.forEach((boardValue, boardIndex)=> {
boardValue.forEach((value,index) => {
score[value] += weights[boardIndex] * votes[index];}) })
// 感覺雛形出來了!來看看結果
console.log(score); //[0, 153, 205, 151, NaN] 恩?

score宣告的時候只給4個值,結果出來變5個值?!

因為scoreBoard出現的數字是1, 2, 3, 4,陣列的索引值從0開始,而score[4] 沒有起始值,undefined + 245(任意數字)= NaN

再修一下就完成了!

1
2
3
4
5
6
7
8
9
10
const votes = [51, 5, 23 , 21]; //票數
const weights = [3, 2, 1, 0]; //權重
const scoreBoard = [[1, 2, 3, 4], [2, 3, 2, 2], [3, 4, 4, 3], [4, 1, 1, 1]];
let score = [0, 0, 0, 0 ,0]; //或[null, 0, 0, 0, 0]

scoreBoard.forEach((boardValue, boardIndex)=> {
boardValue.forEach((value,index) => {
score[value] += weights[boardIndex] * votes[index];}) })

console.log(score); //[0, 153, 205, 151, 91] 跟維基百科說的一樣!*注意人名跟得分

從前輩學來的解題方法覺得很受用
理解題目希望結果的樣子,這兩個一定要先有藍圖,再來想coding使用的方法

新手村時期還在活化大腦階段,只能盡力拆解步驟想辦法找規律了。