sort関連のサンプルコードです。覚書です。
Contents
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
.sort((a, b) => a.localeCompare(b));
文字列比較によるソートです。
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
数値を考慮した文字列比較によるソートです。
サンプルです。
let items = ['項目2', '項目10', '項目1'];
items.sort((a, b) => a.localeCompare(b));
console.log(items);
// 結果: ['項目1', '項目10', '項目2']
let items = ['項目2', '項目10', '項目1'];
items.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
console.log(items);
// 結果: ['項目1', '項目2', '項目10']
localeCompareの使い方
console.log("apple".localeCompare("banana")); // 出力: -1 ("apple" は "banana" より前)
console.log("banana".localeCompare("apple")); // 出力: 1 ("banana" は "apple" より後)
console.log("apple".localeCompare("apple")); // 出力: 0 (同じ文字列)
JavaScript(node.js)で数字込みのファイル名をsortする
const sorted = filenames.sort((a, b) => {
const a1 = parseInt(a.replace(/[^0-9]/g, ''), 10);
const b1 = parseInt(b.replace(/[^0-9]/g, ''), 10);
const a2 = isNaN(a1) ? 0 : a1;
const b2 = isNaN(b1) ? 0 : b1;
if (a2 !== b2) {
return a2 - b2;
}
return a.localeCompare(b);
});
Node.jsでファイル名に数字が含まれる場合のソートを行う際には、Array.prototype.sort()
メソッドを使用しますが、デフォルトのソート機能では文字列として扱われるため、数値の大小関係に基づいたソートが行われません。そのため、数値を含むファイル名を正しくソートするには、比較関数をカスタマイズする必要があります。
数値としてソートすると、以下の順番になります。
a-001.md
(1)a-02.md
(2)3-a.md
(3)a-11.md
(11)3-1.md
(31)7-1.md
(71)3-1-1.md
(311)apple.md
(数字なし、文字列比較)banana.md
(数字なし、文字列比較)
- ファイル名の配列をソートするjavascript
const sorted = filenames.sort((a, b) => {
ここでfilenames
はソートしたいファイル名の配列です。sort
メソッドは配列の要素をソートするために使用され、このメソッドには比較関数が渡されます。比較関数は2つの引数a
とb
を取り、これらを比較してどちらが先に来るべきかを決定します。 - ファイル名から数字のみを抽出して数値に変換するjavascript
const a1 = parseInt(a.replace(/[^0-9]/g, ''), 10); const b1 = parseInt(b.replace(/[^0-9]/g, ''), 10);
ここでは、各ファイル名から数字以外の文字を全て削除(replace(/[^0-9]/g, '')
で実現)し、残った文字列を10進数の整数に変換します(parseInt
関数を使用)。/[^0-9]/g
は正規表現で、数字以外のすべての文字にマッチし、それらを空文字に置換しています。 - 数値変換後のNaNを0に置き換えるjavascript
const a2 = isNaN(a1) ? 0 : a1; const b2 = isNaN(b1) ? 0 : b1;
parseInt
が数字以外の文字列を変換しようとした場合、結果はNaN
(Not a Number)になります。isNaN
関数を使ってこれをチェックし、NaN
であれば0
に置き換えます。これにより、数字が含まれていないファイル名は数値として0
として扱われます。 - 数値でソートするjavascript
if (a2 !== b2) { return a2 - b2; }
抽出した数値が異なる場合は、その差(a2 - b2
)によってソート順を決定します。この結果が負の値ならa
が先、正の値ならb
が先に来ます。 - 数値が同じ場合は文字列として比較するjavascript
return a.localeCompare(b);
数値が同じか、両方とも数字が含まれていない場合は、localeCompare
メソッドを使用して文字列として自然な順序でソートします。これにより、例えばアルファベット順にソートされます。
node.jsの非同期処理で順番が変わる
sortとは別に非同期処理を行うと順番が入れ替わってしまう可能性があるっぽい。
その場合は、再帰関数processFiles
を導入することで、非同期処理を同期的に行います。
Object.fromEntries(Object.entries(obj).sort())) 追加
ランキングはスコアだけではないでしょうから、考え方としてはオブジェクトのソートでしょう。
objects.keyをソートする場合、この方法だと一行でいけますね。
Object.fromEntries(Object.entries({type2: 10, type3:1, type1:5}).sort())
Object.entriesでオブジェクトを配列化し、ソートした上でまたオブジェクトに変換する感じ。
配列のソート(ランキング化)
配列をソートしようしたら次のエラーがでました。
sort is not a function
配列に統一感がなかったため、配列を統一してランキング化しました。
Obj {"type1":11,"type2":9,"type3":10}
scoreのobjでランキング化したい場合。
const array = Object.keys(obj).map((key) => {
return { score: obj[key] }
})
array.sort((a, b) => {
// return a.score - b.score // 昇順
return b.score - a.score // 降順
})
console.log('ソート済', JSON.stringify(array))
純粋な配列でランキング化したい場合。
const array = Object.keys(obj).map((key) => {
return obj[key]
})
array.sort((a, b) => {
return b - a // 降順
})
console.log('ソート済', JSON.stringify(array))
JavaScriptは配列のソートする際、同値の場合はブラウザにより挙動が違うようなので、その対策も考慮する必要があります。return 0;する(読んだだけで詳しくは未検証)
objのソート(別バージョン)
このobjをそのまま使いたい場合は次のようになります。
Obj {"type1":11,"type2":9,"type3":10}
const entries = Object.entries(obj)
const sorted = entries.sort((a, b) => b[1] - a[1]) // 降順
sortedObj = Object.fromEntries(sorted)
keys = Object.keys(sortedObj)
values = Object.values(sortedObj)
nodeのバージョンに制限がある場合、Object.fromEntriesは使えません。他の命令で代替が必要になったケースがありました。
const entries = Object.entries(obj)
const sorted = entries.sort((a, b) => b[1] - a[1]) // 降順
const sortedObj = Object.assign(
...sorted.map(([key, value]) => ({ [key]: value }))
)
objectをn回文繰り返す
ソートしたオブジェクトからトップ3だけ抽出する場合などに便利です。
Array.from({ length: 3 }, (_, i) => {
console.log('3回数ぶん、繰り返す', _, i)
const best3 = Object.keys(obj)[i]
console.log('best3', best3)
})
length: 3で3回分繰り返します。
_はすべてundefined。
iは0, 1, 2です。
{ length: 3 }だけの指定や_を省くと、すべてundefinedになります。
Rangeを使うやり方など、いろいろなやり方があります。
https://stackoverflow.com/questions/3746725/how-to-create-an-array-containing-1-n
コメント