Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@think49
Last active November 3, 2017 21:07
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save think49/660141 to your computer and use it in GitHub Desktop.
Save think49/660141 to your computer and use it in GitHub Desktop.
natsort.js : 自然順アルゴリズムで配列をソート

natsort.js

概要

配列を「自然順アルゴリズム」でソートします。

使い方

natsort(array [, convertfn])

第一引数に指定された配列を自然順アルゴリズムでソートします。

/**
 * 文字列中に含まれる数字の小さい順にソートする
 */
console.log(JSON.stringify(natsort(['rfc1.txt', 'rfc2086.txt', 'rfc822.txt'])));    // ["rfc1.txt","rfc822.txt","rfc2086.txt"]
console.log(JSON.stringify(natsort(['x2-g8','x2-y7','x8-y8','x2-y08'])));           // ["x2-g8","x2-y7","x2-y08","x8-y8"]

/**
 * 一方の要素値がもう一方の要素値に前方一致する場合、文字列長の長い要素値を後ろに並べる
 */
console.log(JSON.stringify(natsort(['a','a2','a1a','a1b','a10','a0','a20','a1']))); // ["a","a0","a1","a1a","a1b","a2","a10","a20"]

/**
 * 小数も比較できる
 */
console.log(JSON.stringify(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"]

破壊的にソートします。

var array = ['9.01', '13', '0256'];

natsort(array);
console.log(array); // ["9.01", "13", "0256"]

要素値が String 型でなかった場合、String 型に型変換してから比較ソートします。

var array = [
  ['a', 10],       // ToString -> "a,10"
  ['b', 1],        // ToString -> "b,1"
  ['110', 'test'], // ToString -> "110,test"
  ['a', 5],        // ToString -> "a,5"
  ['b', '0718'],   // ToString -> "b,0718"
  ['20', '02']     // ToString -> "20,02"
];
console.log(JSON.stringify(natsort(array)));  // [["20","02"],["110","test"],["a",5],["a",10],["b",1],["b","0718"]

natsort()故意に汎用です。第一引数は配列である必要はなく、配列と同じプロパティを持つオブジェクトであれば、期待通りに動作します。

var object = {0:'rfc1.txt',1:'rfc2086.txt',2:'rfc822.txt',length:3};

console.log(JSON.stringify(natsort(object))); // {"0":"rfc1.txt","1":"rfc822.txt","2":"rfc2086.txt","length":3}

第二引数にコールバック関数を指定する事で、各々の要素の比較対象を変更する事が出来ます。

function convertfn (value) {  // 配列の要素を受け取る
  return value[1];            // 要素値となる配列オブジェクトの "1" プロパティを比較する
}

var array = [
  ['foo', '2175'],
  ['bar', 'a0123'],
  ['num', '100'],
  ['piyo', 'a3'],
  ['n', 'b456'],
  ['b', 'b03']
];

natsort(array, convertfn);
console.log(JSON.stringify(array));  // [["num","100"],["foo","2175"],["piyo","a3"],["bar","a0123"],["b","b03"],["n","b456"]]

Array.prototype.sort

natsort() は基本的に、Array.prototype.sort の仕様に倣っています。 Array.prototype.sort破壊的であり、故意に汎用です。

参考リンク

/**
* natsort.js
* Sort an array using a "natural order" algorithm.
*
* @version 1.2.4
* @author think49
* @license http://www.opensource.org/licenses/mit-license.php (The MIT License)
* @url https://gist.github.com/660141
* @see <a href="http://sourcefrog.net/projects/natsort/">Natural Order String Comparison</a>
*/
var natsort = (function (sort) {
'use strict';
var natCompare = (function (String) {
return function natCompare (string1, string2) {
var reg1, reg2, result1, result2, number1, number2, token1, token2, diff;
string1 = String(string1);
string2 = String(string2);
if (string1 === string2) {
return 0;
}
reg1 = /(\d+(?:\.\d+)?)|\D+/g;
reg2 = /(\d+(?:\.\d+)?)|\D+/g;
while (result1 = reg1.exec(string1), result2 = reg2.exec(string2), result1 && result2) {
number1 = result1[1];
number2 = result2[1];
if (number1 && number2) {
diff = number1 - number2; // ToNumber
if (diff) {
return diff;
}
} else {
token1 = result1[0];
token2 = result2[0];
if (token1 !== token2) {
return token1 > token2 ? 1 : -1;
}
}
}
if (!result1) {
return result2 ? -1 : 0;
}
return 1;
};
}(String));
function createNatCompareWithCallback (convertfn) {
return function (string1, string2) {
return natCompare(convertfn(string1), convertfn(string2));
};
}
return function natsort (array /* [, convertfn] */) {
if (arguments.length > 1 && typeof arguments[1] === 'function') {
return sort.call(array, createNatCompareWithCallback(arguments[1]));
}
return sort.call(array, natCompare);
}
})(Array.prototype.sort);
<!DOCTYPE html>
<head>
<title>test</title>
<style>
</style>
</head>
<body>
<script src="natsort-1.2.4.js"></script>
<script>
'use strict';
console.assert(JSON.stringify(natsort(['rfc1.txt', 'rfc2086.txt', 'rfc822.txt'])) === '["rfc1.txt","rfc822.txt","rfc2086.txt"]');
console.assert(JSON.stringify(natsort(['a','a2','a1a','a1b','a10','a0','a20','a1'])) === '["a","a0","a1","a1a","a1b","a2","a10","a20"]');
console.assert(JSON.stringify(natsort(['x2-g8','x2-y7','x8-y8','x2-y08'])) === '["x2-g8","x2-y7","x2-y08","x8-y8"]');
console.assert(JSON.stringify(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"]');
console.assert(JSON.stringify(natsort({0:'rfc1.txt',1:'rfc2086.txt',2:'rfc822.txt',length:3})) === '{"0":"rfc1.txt","1":"rfc822.txt","2":"rfc2086.txt","length":3}');
console.assert(JSON.stringify(natsort([['a',10],['b',1],['110','test'],['a',5],['b','0718'],['20','02']])) === '[["20","02"],["110","test"],["a",5],["a",10],["b",1],["b","0718"]]');
console.assert(JSON.stringify(natsort(['a1-1','a','a1-3-1','a1-3','a1','a1-10','b1-3','b10'])) === '["a","a1","a1-1","a1-3","a1-3-1","a1-10","b1-3","b10"]');
console.assert(JSON.stringify(natsort([['foo','2175'],['bar','a0123'],['num','100'],['piyo','a3'],['n','b456'],['b','b03']], function (value) { return value[1]; })) === '[["num","100"],["foo","2175"],["piyo","a3"],["bar","a0123"],["b","b03"],["n","b456"]]');
console.assert(JSON.stringify(natsort(['a01-1','a1','b2.0','b2-001'] === '["a1","a01-1","b2.0","b2-001"]')))
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment