39280


javascript(jquery)で配列の中を以下のような順番でソートしたいです。  
A1-1  
A1-3  
A1-3-1  
A1-4  
A2  
A4-1  
A6-3  
A13-1  
A13-2  
A13-3  
A13-11  
A13-14  
A51-2  
しかし文字列の比較を用いてソートすると以下のようになってしまいます。  
A1-1  
A1-3  
A1-3-1  
A1-4  
A13-1  
A13-11  
A13-14  
A13-2  
A13-3  
A2  
A4-1  
A51-2  
A6-3  
最初のような形でソートするにはハイフンで文字列を区切ってそれぞれを数値に変換して比較するしかないのでしょうか。  
現在のソートの処理は以下の通りです。

[code]

    sortedAlphabetListData.sort(
      function(a,b){
        if( a[0] < b[0] ) return -1;
        if( a[0] > b[0] ) return 1;
        return 0;
      }
    );
    
[/code]

コメントいただいた中で、自然順アルゴリズムというものが実現したいものに近いことがわかりました。  
<https://gist.github.com/think49/660141>  
こちらのサイトのライブラリを使ってみたのですが、A23,A3-1という順番で表示されてしまいます。A3-1が先に来てほしいです。  
<https://stackoverflow.com/questions/2802341/javascript-natural-sort-of-
alphanumerical-strings>  
ここのサイトを参考に、以下のようにコードを修正しました。ただし、この方法はIE11以上でないと動かない
ですしSafariでは動かないので使えません。（今回はIE9以上をサポートする必要があります。）

[code]

    var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
    var sortedAlphabetListData = alphabetListData.sort(collator.compare);
    
[/code]

このようにしたところ、以下のようにA1-3-1とA1-3が逆になります。  
A1-1  
A1-3-1  
A1-3

以上、宜しくお願い致します。


CC BY-SA 3.0
2017-11-01T05:21:32.950
39200
2017-11-03T21:24:11.030
2017-11-01T08:10:37.067
question
javascript jquery
javascriptでの配列ソートについて


自然順アルゴリズムで処理できるライブラリがあるようでした  
<https://www.npmjs.com/package/javascript-natural-sort>

例えば node.js で利用する場合

[code]

    npm install javascript-natural-sort
    
[/code]

のようにインストールを行い、`natsort_sample.js` というファイル名で内容を

[code]

    const naturalSort = require("javascript-natural-sort");
    console.log(["A1-1",
    "A1-3",
    "A1-3-1",
    "A1-4",
    "A13-1",
    "A13-11",
    "A13-14",
    "A13-2",
    "A13-3",
    "A2",
    "A4-1",
    "A51-2",
    "A6-3",
    ].sort(naturalSort))
    
[/code]

のように保存して実行すると以下のような結果になりました

[code]

    node natsort_sample.js
    [ 'A1-1',
      'A1-3',
      'A1-3-1',
      'A1-4',
      'A2',
      'A4-1',
      'A6-3',
      'A13-1',
      'A13-2',
      'A13-3',
      'A13-11',
      'A13-14',
      'A51-2' ]
    
[/code]


CC BY-SA 3.0
2017-11-01T09:33:48.323
39212
2017-11-01T09:39:43.987
2017-11-01T09:39:43.987
6026
6026
39200
answer


コメントをして下さった皆様、ありがとうございました。また、私の説明が不足しているせいで皆様に御迷惑をお掛けして申し訳ありませんでした。  
[英語版の方にも同様の質問](https://stackoverflow.com/a/47051217/4698341)をして、回答を得られましたので今後のために載せておきます。  
回答は2個あり、どちらでも今回の要望を実現出来ました。  
ご協力いただきありがとうございました。

[一つ目](https://stackoverflow.com/a/15479354/4698341) (by
[georg](https://stackoverflow.com/users/989121/georg))

[code]

    function naturalCompare(a, b) {
        var ax = [], bx = [];
        a.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) });
        b.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) });
    
        while(ax.length && bx.length) {
            var an = ax.shift();
            var bn = bx.shift();
            var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]);
            if(nn) return nn;
        }
        return ax.length - bx.length;
    }
    test.sort(naturalCompare)
    
[/code]

[二つ目](https://stackoverflow.com/a/47051217/4698341) (by [Nina
Scholz](https://stackoverflow.com/users/1447675/nina-scholz))

[code]

    function customSort(data, order) {
    
        function isNumber(v) {
            return (+v).toString() === v;
        }
    
        var sort = {
                asc: function (a, b) {
                    var i = 0,
                        l = Math.min(a.value.length, b.value.length);
    
                    while (i < l && a.value[i] === b.value[i]) {
                        i++;
                    }
                    if (i === l) {
                        return a.value.length - b.value.length;
                    }
                    if (isNumber(a.value[i]) && isNumber(b.value[i])) {
                        return a.value[i] - b.value[i];
                    }
                    return a.value[i].localeCompare(b.value[i]);
                },
                desc: function (a, b) {
                    return sort.asc(b, a);
                }
            },
            mapped = data.map(function (el, i) {
                var string = el.replace(/\d(?=[a-z])|[a-z](?=\.)/gi, '$&. .'),
                    regex = /(\d+)|([^0-9.]+)/g,
                    m,
                    parts = [];
    
                while ((m = regex.exec(string)) !== null) {
                    parts.push(m[0]);
                }
                return { index: i, value: parts, o: el, string: string };
            });
    
        mapped.sort(sort[order] || sort.asc);
        return mapped.map(function (el) {
            return data[el.index];
        });
    }
    
    var array = ['A1-1', 'A1-3', 'A1-3-1', 'A1-4', 'A2', 'A4-1', 'A6-3', 'A13-1', 'A13-2', 'A13-3', 'A13-11', 'A13-14', 'A51-2'];
    
    console.log(customSort(array));
    console.log(customSort(array, 'desc'));
    
[/code]


CC BY-SA 3.0
2017-11-02T04:44:48.713
39239
2017-11-02T14:03:07.843
2017-11-02T14:03:07.843
2376
39200
answer


> <https://gist.github.com/think49/660141>  
>  こちらのサイトのライブラリを使ってみたのですが、A23,A3-1という順番で表示されてしまいます。A3-1が先に来てほしいです。

配布元の作者です。  
現象を再現できた為、natsort-1.2.4.js で修正しました。

  * [natsort.js : 自然順アルゴリズムで配列をソート](https://gist.github.com/think49/660141)

要件は満たしていると思います。

[code]

    natsort(["A13-1","A13-3","A13-14","A4-1","A13-11","A1-1","A13-2","A51-2","A2","A1-3","A6-3","A1-3-1","A1-4"]); // ["A1-1","A1-3","A1-3-1","A1-4","A2","A4-1","A6-3","A13-1","A13-2","A13-3","A13-11","A13-14","A51-2"]
    
[/code]

[Natural Order String
Comparison](http://sourcefrog.net/projects/natsort/)のサンプルでも要件を満たします。

[code]

    natsort(['a','a2','a1a','a1b','a10','a0','a20','a1']);  // ["a","a0","a1","a1a","a1b","a2","a10","a20"]
    natsort(['1.02','1.002','1.3','1.001','1.1','1.010']);  // ["1.001","1.002","1.010","1.02","1.1","1.3"]
    natsort(['x2-g8','x2-y7','x8-y8','x2-y08']);            // ["x2-g8", "x2-y7", "x2-y08", "x8-y8"]
    natsort(['1.02','1.002','1.3','1.001','1.1','1.010']);  // ["1.001", "1.002", "1.010", "1.02", "1.1", "1.3"]
    
[/code]

Re: FESHIMO さん


CC BY-SA 3.0
2017-11-03T18:52:47.273
39280
2017-11-03T21:24:11.030
2017-11-03T21:24:11.030
20262
20262
39200
answer