iT邦幫忙

5

JS 的物件屬性名稱如果是 '001' '011' '111' 這樣的數字字串,排列順序是怎麼決定,有辦法控制嗎?

會有這個問題是因為要查銀行代碼去對銀行名稱
想要回傳 JSON 物件

把 xml parser 後得到的結果類似是這樣

bankCode: {
  '004':'臺灣銀行',
  '005':'臺灣土地銀行',
  '102':'華泰商業銀行',
  '103':'臺灣新光商業銀行',
  ...
}

但回傳的時候 '004' 跟 '005' ,或說 0 開頭的都會排在最後面,而且就不排序了

所謂不排序是像這樣

bankCode: {
  '005':'臺灣銀行',
  '004':'臺灣土地銀行',
  '103':'華泰商業銀行',
  '102':'臺灣新光商業銀行',
}

JSON.stringify(bankCode) => {'102','103','005','004'} 
// 102&103 有排, 005&004 沒排而且順位被擠到後面

看起來像是 1~9 開頭的數字字串會被當成 Number 來排序,0 開頭的會被視為一般字串,在列出物件的屬性時會被移到 Number 後面,順序則按照本來的順序。有什麼方法可以讓 property name 為 '0' 開頭的數字(e.g. '001' '0011') 照順序排嗎(物件的形式)?

我本來的做法是先 Object.keys(bankCode).sort((a,b)=>a-b) 把 key 取出來轉 array 再排序,然後用排序過的 array 跑迴圈按照順序把屬性加到新物件上

像這樣

const sortedArray = Object.keys(bankCode).sort((a,b)=>a-b)
const newObj = {}

for(i = 1; i < sortedArray.length; i++){
  newObj[sortedArray[i]] = bankCode[sortedArray[i]]
}

嘗試了一些方法後覺得好像辦不到也想不到其他方式了,就想說來問看看…另外像這樣的問題我如果要探究原因或找英文討論,關鍵字應該怎麼下比較好?用 object property sort number 之類的組合好像都沒看到類似的問題 orz

froce iT邦大師 3 級 ‧ 2020-01-08 06:47:41 檢舉
js的object是無序的,所以排序沒啥必要,就把keys取出來排序,要用時再去得對應值就好。
要說沒必要也好像是沒必要,只是做 api 的時候看到自己傳出去的東西順序排成這樣覺得不舒服 XD
12
fillano
iT邦超人 1 級 ‧ 2020-01-08 10:51:55
最佳解答

如果是要在JSON.stringify印出的物件讓他排序:

JSON.stringify(bankCode, Object.keys(bankCode).sort());

即可。

看更多先前的回應...收起先前的回應...
fillano iT邦超人 1 級 ‧ 2020-01-08 11:00:37 檢舉

如果是想讓他在for迴圈可以依照key順序迭代,可以實作iterator,然後用for...of語法來迭代物件:

let bankCode = {
    '103':'華泰商業銀行',
    '005':'臺灣銀行',
    '102':'臺灣新光商業銀行',
    '011':'彰化銀行',
    '004':'臺灣土地銀行',
};
bankCode[Symbol.iterator] = function*() {
    let keys = Object.keys(this).sort();
    for(let i=0; i< keys.length; i++) {
        yield keys[i];
    }
};
for(let i of bankCode) {
	console.log(`key: ${i}, value: ${bankCode[i]}`);
}

JSON.stringify(bankCode, Object.keys(bankCode).sort());

這個也太神奇了 Q_Q 我後來決定的作法就是自己組 JSON String ,沒想到還有這種用法。常常在提醒自己要多看原生 API ,學到這種東西就會覺得很該死 orz

實作迭代這內容好多不認識的東西,又多學到了,感恩 <(_ _)>

fillano iT邦超人 1 級 ‧ 2020-01-08 15:03:24 檢舉

研究了一下,發現可以用yield*來delegate另外一個generator或是iterable。因為陣列是iterable,所以上面的iterator可以寫成一行:

bankCode[Symbol.iterator] = function*() {
    yield * Object.keys(this).sort();
}
良葛格 iT邦新手 4 級 ‧ 2020-01-08 15:09:34 檢舉
fillano iT邦超人 1 級 ‧ 2020-01-08 16:32:54 檢舉

XD

3
阿展展展
iT邦好手 1 級 ‧ 2020-01-08 05:30:50

印出來之前,轉成數字 (parsInt) 之後再排序 (sort)
如果仍然不是你要的順序 那把 sort 的條件設得更嚴謹一點

注意:你要排序的只有 key,也就是 '005':'臺灣銀行' 中的 '005'
當 key 的排序正常之後, key : value 的對應表就簡單多惹

看更多先前的回應...收起先前的回應...

印出來之前,轉成數字 (parsInt)

'005' -> 5
'004' -> 4
'103' -> 103
'102' -> 102

之後再排序 (sort)

102
103
4
5

key : value 的對應表

 '102':'華泰商業銀行',
 '103':'臺灣新光商業銀行',
 '4':undefined,
 '5':undefined,

parsInt 後 前方補0的銀行都會出事
004臺灣銀行
005土地銀行
006合庫商銀
007第一銀行
008華南銀行
009彰化銀行
011上海銀行
.
.
.
072德意志銀行
075東亞銀行
081永豐銀行

你要把 00x 的 跟 0xx 的另外寫判別
就是我原本說的「 sort 的條件設得更嚴謹一點」

然後印出來時再把0補回去

其實直接 Object.keys(obj).sort() 出來的順序就是正確的,sort 的部份我就沒想過要處理…

只是從 Object 拿出來或是轉成 JSON.stringify 之後順序不對orz

js 的神奇之處 (X

3
dragonH
iT邦大師 1 級 ‧ 2020-01-08 10:36:30

剛試了一下

就算你把開頭為 0 跟 非為 0 的分開排序

最後在合併

他也是會把 1xx 放到前面

真要排序

可以考慮把它弄成另一種資料型態

codepen

看更多先前的回應...收起先前的回應...

重音符號 太潮惹` `

神奇的是 .. codepen 直接把 object 印出來就是我想要的順序 XD
但開 chrome console 印出來結果跟 node.js 中都一樣會把 0 開頭排到後面

第一種作法好有趣, 學到新的組合方式了 :D, 然後還學到startsWith Orz

第二種做成物件陣列我有想過, 但覺得不是我想要的

是說 .. 重音符號是指什麼 ?_?

=> ` <= 這個

忽然看懂潮在哪裡了 XD

2
ccutmis
iT邦高手 8 級 ‧ 2020-01-08 11:33:19

土砲作法提供您參考。

<!DOCTYPE html>
<html lang="zh-tw">
<head><meta charset="utf-8"><title>Untitled</title></head>
<body>
<script>
const bankCode= {
  '005':'臺灣土地銀行',
  '103':'臺灣新光商業銀行',
  '004':'臺灣銀行',
  '102':'華泰商業銀行'
};

const keys = Object.keys(bankCode);
console.log(keys.sort());
// ["004", "005", "102", "103"]
document.write(keys.sort());

let bankCodeArr=[];
keys.forEach( el => bankCodeArr.push([ el,bankCode[el] ]) );
console.log(bankCodeArr[0]);
// ["004", "臺灣銀行"]
document.write('<br/>'+bankCodeArr);

</script>
</body>
</html>

我個人的感想是你需要先對陣列(Array)與字典(Dictionary)的用法有一些理解,javascript的物件屬性在這裡的例子用起來就像字典(用key去取值),通常是不需要去把它排序的(也無法排序,因為字典的特性就是這樣),
例如你有一個銀行代碼'005',
用bankCode['005']去查詢出銀行名稱是最快的(big o=1)
如果把字典轉換成陣列再用陣列去查詢反而慢(big o=陣列長度)。
如果對上面的陣列與字典的用法理解之後,
你會知道 你問的這個問題本身就有問題

我懂你的意思 ~ 其實我也知道 object 本身就沒辦法排序

但當今天要輸出的時候,例如 console.log 來印物件或者做 JSON.stringify ,甚至 Object.keys(),都還是會有一個方法去決定用什麼順序輸出 key:value

原本想嘗試的是能透過什麼產生方式可以讓輸出的結果順序受控,在不考慮數字字串的情況下,順序就是按照屬性加入的順序排。

所以其實排序時有問題的不是 0 開頭的數字字串,而是 1~9 開頭的數字字串被另外處理了。

我要發表回答

立即登入回答