iT邦幫忙

4

如何解決 JavasSript [7,-2,2,-7,-3].sort() = [-2,-3,-7,2,-7] 問題

[7,-2,2,-7,-3].sort() = [-2,-3,-7,2,-7]

xxx

以下是前端FB社團看到的解釋 :

因為 JavaScript 預設的比較函式是
(a, b) => a.toString().localeCompare(b)
也就是先將輸入轉為字串 (所以上述就是 "-" 排在數字之前比較,第二個字元再來比順序),並依據區域化設定而會不同的排序結果 —— 舉例來說,如果你的語系設定為捷克語 (分類上算是西斯拉夫語支),以 "CH" 開頭的字串要排在 "H" 之後,但單看字母的話,"C" 要在 "B" 之後。
光是排序的規則就可以探討一陣子,我們該如何誠實面對自身對 JavaScript 的無力呢?

想請問大家怎麼解決JS的排序問題呢?
有推薦的第三方庫?


更新

嘗試第一種方式 : JavaScript中sort方法排序不正確解決辦法_weixin_36309908的博客-CSDN博客

var arr = [7,-2,2,-7,-3];
arr.sort(function (a,b) {
    if (a < b ) return -1;
    if (a > b ) return 1;
    return 0;
});

結果 : 可以,但需要每一次排序自己實現方法
xxx

嘗試2 : 從 V8 源碼看 JS 數組排序的詭異問題 - 前端進階 - SegmentFault 思否

var arr = [7,-2,2,-7,-3];
arr.sort((x, y) => x - y);

結果 : OK,而且也簡短好多,但會有先map再sort先sort再map結果可能會不一樣問題,貞操蛋 = v =

文中補充 :

如果 comparefn(a, b) 等於 0ab 的相對位置不變。備註:ECMAScript 標準並不保證這一行為,而且也不是所有瀏覽器都會遵守。
翻譯成編程術語就是:sort 排序算法是不穩定排序。

xxx
先map再sort先sort再map結果可能會不一樣問題

//異常排序
var data = [
  {value: 4}, 
  {value: 2}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 1}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 7}, 
  {value: undefined}, 
  {value: 4}
];

data
  .sort((x, y) => x.value - y.value)
  .map(x => x.value);
// result : (10) [2, 4, undefined, undefined, 1, undefined, undefined, 4, 7, undefined]


//能正常排序
var data = [
  {value: 4}, 
  {value: 2}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 1}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 7}, 
  {value: undefined}, 
  {value: 4}
]; 

data
  .map(x => x.value)
  .sort((x, y) => x.value - y.value);
// result : [4, 2, 1, 7, 4, undefined, undefined, undefined, undefined, undefined]

嘗試 3 : 

listennn08 :
lodash
_.sortBy(data, (el) => el.value)

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script>
//能正常排序
var data = [
  {value: 4}, 
  {value: 2}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 1}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 7}, 
  {value: undefined}, 
  {value: 4}
]; 

var sorted = 
	_.map(
      _.sortBy(data, (el) => el.value)
      ,(el) => el.value
    )
;     
        
console.log(sorted);//[1, 2, 4, 4, 7, undefined, undefined, undefined, undefined, undefined] 
</script>

結果 : 目前測試以來效果最好的
文件 : lodash.map | Lodash 中文网

看更多先前的討論...收起先前的討論...
給你一個考題:
為何排序後,1會比10大或是前面?
什麼情況下會發生這種事。

在看別人的東西學習時,也得了解人家為何要這樣寫才行。
上面的考題,知道答案的先不要說。我想讓樓主去找這個答案。
畢竟這是一個很簡單的觀念。會的人一定很多。
ke11vin30 iT邦新手 5 級 ‧ 2020-09-14 15:27:39 檢舉
sort 中可以擺想要的順序~
hokou iT邦新手 5 級 ‧ 2020-09-14 15:30:25 檢舉
[1,2,5,10].sort((a, b) => a - b)

找到的:https://blog.csdn.net/shadow_zed/article/details/82804800
感謝前輩們,但目前找到的原生sort解決方案,都多多少少會有兼容性問題
所以想問是否有推薦的第三方套件呢?
這種東西沒有所謂的第三方套件。等你回答我給你的題目。你自然就會知道為何不可能有第三方套件了。及為何會有可能性跑掉的問題了。

「為何1會比10大」,這就是排序第一個要面臨的問題。
疑,為何1會比10大,這點我測試不對 @@
是10>1
```
[1,10,3].sort();
(3) [1, 10, 3]
```
lodash
_.sortBy(data, (el) => el.value)

你之前的問題就有用到這個函式庫 麻煩好好看看他

你上面問題的回答跟你秀出來的結果不太一樣
1 在 10 前面 3 在 10 後面 有發現了嗎?
您好,listennn08 大神
請問可以底下留言嗎? 您的答案解決我的問題

2 個回答

3
wrxue
iT邦新手 2 級 ‧ 2020-09-14 15:27:33
最佳解答
Array.prototype.mysort = function() {
    return this.sort(function(a, b) {
         return a - b;
    })
}

[7,-2,2,-7,-3, 27].mysort()
output -> [-7, -3, -2, 2, 7, 27]

感謝您
我目前找到最簡短的也是這樣,但看這篇文章 从 V8 源码看 JS 数组排序的诡异问题 - 前端进阶 - SegmentFault 思否 此方式會有以下問題
先map再sort跟先sort再map結果可能會不一樣

但這應該算是另外新的問題了

//異常排序
var data = [
  {value: 4}, 
  {value: 2}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 1}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 7}, 
  {value: undefined}, 
  {value: 4}
];

data
  .sort((x, y) => x.value - y.value)
  .map(x => x.value);
// result : (10) [2, 4, undefined, undefined, 1, undefined, undefined, 4, 7, undefined]


//能正常排序
var data = [
  {value: 4}, 
  {value: 2}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 1}, 
  {value: undefined}, 
  {value: undefined}, 
  {value: 7}, 
  {value: undefined}, 
  {value: 4}
]; 

data
  .map(x => x.value)
  .sort((x, y) => x.value - y.value);
// result : [4, 2, 1, 7, 4, undefined, undefined, undefined, undefined, undefined]
4
淺水員
iT邦研究生 4 級 ‧ 2020-09-14 17:08:14

但目前找到的原生sort解決方案,都多多少少會有兼容性問題

這不算是兼容性問題,是沒有定義好 undefined 在比較時要怎麼處理
定義好結果就會正確了

var data = [
    {value: 4}, 
    {value: 2}, 
    {value: undefined}, 
    {value: undefined}, 
    {value: 1}, 
    {value: undefined}, 
    {value: undefined}, 
    {value: 7}, 
    {value: undefined}, 
    {value: 4}
]; 

data.sort((a, b)=>{
    var type_a = typeof a.value ==='number' ? 0 : 1;
    var type_b = typeof b.value ==='number' ? 0 : 1;
    if(type_a|type_b) {
        return type_a-type_b;
    }
    return a.value-b.value;
});
淺水員 iT邦研究生 4 級 ‧ 2020-09-14 17:27:18 檢舉

另外,如果想保證當數值相同時,順序會不變,也可以自己寫一個函式。

function stableSort(arr, cmpFunc) {
    let wrapArray=arr.map((v,i)=>{
        return {idx:i, val:v}
    });
    wrapArray.sort((a, b)=>{
        var cmp=cmpFunc(a.val, b.val);
        return cmp===0?a.idx-b.idx:cmp;
    });
    wrapArray.forEach((x,i)=>{
        arr[i]=x.val;
    });
    return arr;
}

感謝 淺水員 大神!

我要發表回答

立即登入回答