跳至內容
Astera Technology

排序後保留原陣列,分數相同也有固定次序

先複製再按數字排序,分數相同時保留輸入先後。

下載完整個案資料及參考答案 ↓

先追這段程式

A 是 10 分,B、C 都是 2 分。排序由低至高,但來源仍要是 A、B、C;同分的 B、C 保留原先次序。

完整原始程式
const source=[{id:'A',score:10},{id:'B',score:2},{id:'C',score:2}];
const sorted=[...source].sort((a,b)=>a.score-b.score);
console.log(JSON.stringify({sorted:sorted.map(r=>r.id),source:source.map(r=>r.id)}));
確實的 console 輸出
{"sorted":["B","C","A"],"source":["A","B","C"]}
值與執行位置
資料列分數排序後位置
B2最前
C2與 B 同分,排在其後
A10最後

結果為何如此

sort 會改接收它的陣列;先展開成新陣列,才不會移動來源。比較函式用數字相減,同分傳回零,穩定排序保留先後。列物件仍共用;NaN 分數或不一致的比較規則要另訂處理方式。

比較另一種寫法

直接 source.sort 會改來源;不給比較函式,這組數字按文字方式排,10 反而在 2 之前。

另開的有限例子
const source=[10,2];const result=source.sort();
console.log(JSON.stringify({source,result,sameArray:source===result}));
另一寫法的輸出
{"source":[10,2],"result":[10,2],"sameArray":true}

試清邊界

排序陣列明明是新的,為甚麼 B 物件仍共用?

查看參考答案

展開複製的是陣列項目的物件參照,所以保留原陣列次序,不會隔離各列內部修改。

重新建立的邊界例子
const source=[{id:'A',score:10},{id:'B',score:2}];const sorted=[...source].sort((a,b)=>a.score-b.score);
const direct=[10,2];direct.sort((a,b)=>a-b);
console.log(JSON.stringify({differentArray:sorted!==source,sameB:sorted[0]===source[1],sourceIds:source.map(r=>r.id),direct}));
邊界例子的輸出
{"differentArray":true,"sameB":true,"sourceIds":["A","B"],"direct":[2,10]}

原始例子檔案