Object.keys()
, Object.values()
, & Object.entries()
這篇的起因是 AC 2–1 期末的技術驗收題目中,其中一題是需要撰寫一段程式,將 1~3999 的正整數,轉換成羅馬字。這一題要自己設計資料結構。
問題
由於羅馬數字有7個,即 Ⅰ(1)、Ⅴ(5)、Ⅹ(10)、Ⅼ(50)、Ⅽ(100)、Ⅾ(500)和 Ⅿ(1000),但是遇到 4, 9 要把符號放左邊(右加左減),覺得這樣一下左一下右有點複雜,所以把它放在資料裡。所以這題有以下需求:(1) 資料結構如下圖,(2) 演算法要從數字大到數字小依序處理:

羅馬數字的規則參考
思考
在課程中比較多使用 array 來進行迴圈迭代,所以第一次交的版本,是把羅馬文字跟十進位數字照順序放在兩個 array 裡面,這樣 loop 的時候同一個 index 可以對應到羅馬字與數字。(寫的時候還不會用 forEach )
1 2 3 4 5 6 7 8 9 10 11 12 13
| function toRoman(inputNum) { let romanNum = '' let remainder = Number(inputNum) const romanArray = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'] const decimalArray = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] for (let i = 0; i < romanArray.length; i++) { while (remainder >= decimalArray[i]) { let count = Math.floor(remainder / decimalArray[i]) romanNum = romanNum + romanArray[i].repeat(count) remainder = remainder % decimalArray[i] } } return romanNum
|
因為覺得放兩個 array 還要仔細看兩個 array 有沒有缺漏造成對應錯誤,還是用 key-value 結構比較直覺。助教提示我:其實 object 也可以放到 array 裡啊~所以我就來試試(這時候已經會用 forEach 跟 arrow function 了!)。
這個資料結構是 array 裡放 object,照順序取出 object,用 Object.keys()
與 Object.values()
取物件裡的東西。由於每個 object 裡都只有一個 key-value pair,所以[]
裡的 index 值都是 0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function toRoman(inputNum) { let romanNum = '' let remainder = Number(inputNum) const numPairs = [ {'M': 1000}, {'CM': 900}, {'D': 500}, {'CD': 400}, {'C': 100}, {'XC': 90}, {'L': 50}, {'XL': 40}, {'X': 10}, {'IX': 9}, {'V': 5}, {'IV': 4}, {'I': 1} ]
numPairs.forEach(pairObj => { while (remainder >= Object.values(pairObj)[0]) { let count = Math.floor(remainder / Object.values(pairObj)[0]) romanNum = romanNum + Object.keys(pairObj)[0].repeat(count) remainder = remainder % Object.values(pairObj)[0] } }) return romanNum }
|
繼續嘗試
真的不能用單純 object,然後叫他照順序來嗎!?我繼續來試~
Object.entries()
這個方法會將 object 回傳成雙層 array,再搭配 for..of
迴圈(跟之前 Python 裡面寫 for k, v in object: 一樣的功能)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function toRoman(inputNum) { let romanNum = '' let remainder = Number(inputNum) const numPairs = { 'M': 1000, 'CM': 900, 'D': 500, 'CD': 400, 'C': 100, 'XC': 90, 'L': 50, 'XL': 40, 'X': 10, 'IX': 9, 'V': 5, 'IV': 4, 'I': 1, } for (const [r, a] of Object.entries(numPairs)) { while (remainder >= a) { let count = Math.floor(remainder / a) romanNum = romanNum + r.repeat(count) remainder = remainder % a } } return romanNum }
|
結論
條條大路通羅馬(文字)XD
後記
寫的時候在想,現在是我先把羅馬字與數字的對應從大到小放進去了,如果到時候 object 進來是從小到大,甚至是亂排,應該有方法是可以 sorting 先把 value 照大小排序的(覺得後面應該會學到)。