辞書順ソートにしたい
Intl.Collatorは便利だけど、「辞書順」にはソートしてくれないっぽい。
辞書順って、個人的観測では、目次を連想するので最初の1文字でグルーピングする感じかなっということで。
元ネタを用意
今度は違うゲーム攻略サイト情報で「アズールレーン」から引用してみた。
ソートの元ネタ
20%以下
5.0%アップ同じスキル
15.0%アップ同じスキル
20秒毎重巡級
10秒毎重巡級
30%ダウン
60%ダウン
15.0%アップ
35.0%アップ
20%以下
15.0%回復
25.0%回復
40.0%アップ
5.0%アップ同じ種類
15.0%アップ同じ種類
2回発射
20.0%アップ同じスキル
40.0%アップ同じスキル
5%アップ同じ種類
50.0%アップ
20.0%軽減
100.0%アップ
30.0%軽減
20秒毎15.0発動6秒間自身
30.0%アップ
60%アップ
31ノット・バーク
20.0%アップ
40.0%アップ
35秒毎特殊魚雷
3発発射
20.0%分
25秒毎特殊魚雷
30.%アップ
60.0%アップ
10秒毎40.0%発動8秒間自身
60.0%アップ
6.0%アップ
18.0%アップ
10.0%アップ
1.0%アップ同じ種類
10.0%アップ同じ種類
12回攻撃
20.0%上昇同じスキル
40.0%上昇同じスキル
5%軽減
15%軽減
5.0%軽減
15.0%軽減
25.0%アップ
50%アップ
8回攻撃
5.0%アップ
5%アップ同じスキル
25%アップ同じスキル
40.0%ダウン
20.0%ダウン
15%回復
40.0%ダウン
10攻撃
15.0%アップ
9回攻撃
6回攻撃
5.0%軽減同じスキル
15.0%軽減同じスキル
30秒毎発動5秒間敵弾
2枚生成
30秒毎発動15秒間敵弾
50%軽減
50%軽減
30秒毎
15%アップ
35%アップ
20%アップ
40%アップ
15.0%アップ魚雷発射時15.0%
25.0%アップ魚雷発射時30.0%
20秒毎前方
4.0%回復
10.0%回復
5.0%ダウン
15.0%ダウン
35秒毎前方
15秒毎前方
3.5%回復
8.0%回復
30%アップ
10.0%回復エンタープライズ
20.0%回復エンタープライズ
5.0%増加
15.0%増加
20秒毎
4.0%装填・命中
5.0%アップ重桜所属空母
5.0%アップ
10.0%装填・命中
20.0%アップ重桜所属空母
20%
8秒間味方艦
8.0%アップ
8秒間対象
1.2%回復
3.0%回復
30%
20%アップ
60%
40%アップ
10%アップ
30%アップ
40%ダウン
20%ダウン
16.0%上昇空襲ダメージ16.0%軽減
40.0%上昇空襲ダメージ40.0%軽減
20%ダウン艦隊内
4%アップ
10%アップ魚雷クリティカルダメージ
5%アップ
15.0%雷装
4.0%アップ
30.0%雷装
10.0%アップ
20秒毎30.0%
20秒毎60.0%
70%
30%以下
70%以下
35%アップ
15%ダウン
10%ダウン
5.0%軽減
15.0%軽減
10.0%ダウン
10.0%回避
25.0%回避
4.5%アップ
12.0%アップ
4.0%アップ
10.0%軽減
65%アップ
5%アップ
3秒間増加自身
15%軽減
6秒間20%減速
6秒間40%減速
0.6アップ耐久
3%回復
1アップ耐久
25.0%軽減
5.0%アップ効果適用中
25.0%アップ効果適用中
24回攻撃
16回攻撃
5.0%雷装
15.0%雷装
5.0%アップまた自身へ
20.0%アップまた自身へ
Intl.Collator での比較用に数値ソートした結果
前回と同じような実装内容で、こんな感じ。
const words = [
*ソート元ネタたち*
]
export function sortEx03() {
const jaCollator = new Intl.Collator('ja', {
numeric: true,
});
const isAsc = true
const sorted = words.sort((a, b) => {
return isAsc
? jaCollator.compare(a, b)
: jaCollator.compare(b, a)
})
sorted.forEach(w => { console.log(w) })
}
ソート結果(Intl.Collator)
0.6アップ耐久
1.0%アップ同じ種類
1.2%回復
1アップ耐久
2回発射
2枚生成
3.0%回復
3.5%回復
3%回復
3発発射
3秒間増加自身
4.0%アップ
4.0%アップ
4.0%回復
4.0%装填・命中
4.5%アップ
4%アップ
5.0%アップ
5.0%アップ
5.0%アップ,効果適用中
5.0%アップまた自身へ
5.0%アップ重桜所属空母
5.0%アップ同じスキル
5.0%アップ同じ種類
5.0%ダウン
5.0%軽減
5.0%軽減
5.0%軽減同じスキル
5.0%増加
5.0%雷装
5%アップ
5%アップ
5%アップ同じスキル
5%アップ同じ種類
5%軽減
6.0%アップ
6回攻撃
6秒間20%減速
6秒間40%減速
8.0%アップ
8.0%回復
8回攻撃
8秒間対象
8秒間味方艦
9回攻撃
10.0%アップ
10.0%アップ
10.0%アップ同じ種類
10.0%ダウン
10.0%回避
10.0%回復
10.0%回復エンタープライズ
10.0%軽減
10.0%装填・命中
10%アップ
10%アップ魚雷クリティカルダメージ
10%ダウン
10攻撃
10秒毎40.0%発動8秒間自身
10秒毎重巡級
12.0%アップ
12回攻撃
15.0%アップ
15.0%アップ
15.0%アップ魚雷発射時15.0%
15.0%アップ同じスキル
15.0%アップ同じ種類
15.0%ダウン
15.0%回復
15.0%軽減
15.0%軽減
15.0%軽減同じスキル
15.0%増加
15.0%雷装
15.0%雷装
15%アップ
15%ダウン
15%回復
15%軽減
15%軽減
15秒毎前方
16.0%上昇空襲ダメージ16.0%軽減
16回攻撃
18.0%アップ
20.0%アップ
20.0%アップまた自身へ
20.0%アップ重桜所属空母
20.0%アップ同じスキル
20.0%ダウン
20.0%回復エンタープライズ
20.0%軽減
20.0%上昇同じスキル
20.0%分
20%
20%アップ
20%アップ
20%ダウン
20%ダウン艦隊内
20%以下
20%以下
20秒毎
20秒毎15.0発動6秒間自身
20秒毎30.0%
20秒毎60.0%
20秒毎重巡級
20秒毎前方
24回攻撃
25.0%アップ
25.0%アップ,効果適用中
25.0%アップ魚雷発射時30.0%
25.0%回避
25.0%回復
25.0%軽減
25%アップ同じスキル
25秒毎特殊魚雷
30.%アップ
30.0%アップ
30.0%軽減
30.0%雷装
30%
30%アップ
30%アップ
30%ダウン
30%以下
30秒毎
30秒毎発動5秒間敵弾
30秒毎発動15秒間敵弾
31ノット・バーク
35.0%アップ
35%アップ
35%アップ
35秒毎前方
35秒毎特殊魚雷
40.0%アップ
40.0%アップ
40.0%アップ同じスキル
40.0%ダウン
40.0%ダウン
40.0%上昇空襲ダメージ40.0%軽減
40.0%上昇同じスキル
40%アップ
40%アップ
40%ダウン
50.0%アップ
50%アップ
50%軽減
50%軽減
60.0%アップ
60.0%アップ
60%
60%アップ
60%ダウン
65%アップ
70%
70%以下
100.0%アップ
辞書順の考察
目次を連想して最初の1文字でグルーピングする感じで実装変更してみた。
正規表現を使って数値かの判定をするイメージ。
正規表現のマッチング文字列はGeminiにおしえてもらった(#^.^#)。
export interface NumericInfo {
isNumeric: boolean; // 数値で始まっているか
value: number; // 変換後の数値(1, 10, 100 など)
firstChar: string; // 先頭の1文字 ('1', '2' など)
}
/**文字列の先頭が数値から始まっているか */
function isNumericStarting(text: string): NumericInfo {
const match = text.match(/^[+-]?[0-9]+(?:\.[0-9]+)?/)
if (match) {
const numVal = Number(match[0])
if (!isNaN(numVal)) {
return { isNumeric: true, value: numVal, firstChar: match[0].charAt(0) }
}
}
// 数字で始まらない場合
return { isNumeric: false, value: -1, firstChar: `` }
}
比較関数を呼び出す。
export function sortEx04() {
const isAsc = true
const sorted = words.sort((a, b) => {
const aN = isNumericStarting(a)
const bN = isNumericStarting(b)
if (aN.isNumeric && bN.isNumeric) {
if (aN.firstChar === bN.firstChar) //先頭1文字が同じ場合、数値比較
return isAsc ? aN.value - bN.value : bN.value - aN.value
}
return a.localeCompare(b)
})
sorted.forEach(w => { console.log(w) })
}
ソート結果(辞書順考慮)
0.6アップ耐久
1.0%アップ同じ種類
1アップ耐久
1.2%回復
10秒毎重巡級
10秒毎40.0%発動8秒間自身
10.0%アップ
10.0%アップ同じ種類
10攻撃
10.0%回復
10.0%回復エンタープライズ
10.0%装填・命中
10%アップ
10%アップ魚雷クリティカルダメージ
10.0%アップ
10%ダウン
10.0%ダウン
10.0%回避
10.0%軽減
12回攻撃
12.0%アップ
15.0%アップ同じスキル
15.0%アップ
15.0%回復
15.0%アップ同じ種類
15%軽減
15.0%軽減
15%回復
15.0%アップ
15.0%軽減同じスキル
15%アップ
15.0%アップ魚雷発射時15.0%
15.0%ダウン
15秒毎前方
15.0%増加
15.0%雷装
15%ダウン
15.0%軽減
15%軽減
15.0%雷装
16.0%上昇空襲ダメージ16.0%軽減
16回攻撃
18.0%アップ
100.0%アップ
2回発射
2枚生成
20%以下
20秒毎重巡級
20%以下
20.0%アップ同じスキル
20.0%軽減
20秒毎15.0発動6秒間自身
20.0%アップ
20.0%分
20.0%上昇同じスキル
20.0%ダウン
20%アップ
20秒毎前方
20.0%回復エンタープライズ
20秒毎
20.0%アップ重桜所属空母
20%
20%アップ
20%ダウン
20%ダウン艦隊内
20秒毎30.0%
20秒毎60.0%
20.0%アップまた自身へ
24回攻撃
25.0%回復
25秒毎特殊魚雷
25.0%アップ
25%アップ同じスキル
25.0%アップ魚雷発射時30.0%
25.0%回避
25.0%軽減
25.0%アップ,効果適用中
3発発射
3.0%回復
35%アップ
3秒間増加自身
3%回復
3.5%回復
30%ダウン
30.0%軽減
30.0%アップ
30.%アップ
30秒毎発動5秒間敵弾
30秒毎発動15秒間敵弾
30秒毎
30%アップ
30%
30%アップ
30.0%雷装
30%以下
31ノット・バーク
35.0%アップ
35秒毎特殊魚雷
35%アップ
35秒毎前方
4.0%回復
4.0%装填・命中
4%アップ
4.0%アップ
4.0%アップ
4.5%アップ
40.0%アップ
40.0%アップ同じスキル
40.0%アップ
40.0%上昇同じスキル
40.0%ダウン
40.0%ダウン
40%アップ
40%アップ
40%ダウン
40.0%上昇空襲ダメージ40.0%軽減
5.0%アップ同じスキル
5.0%アップ同じ種類
5%アップ同じ種類
5%軽減
5.0%軽減
5.0%アップ
5%アップ同じスキル
5.0%軽減同じスキル
5.0%ダウン
5.0%増加
5.0%アップ重桜所属空母
5.0%アップ
5%アップ
5.0%軽減
5%アップ
5.0%アップ,効果適用中
5.0%雷装
5.0%アップまた自身へ
50.0%アップ
50%アップ
50%軽減
50%軽減
6.0%アップ
6回攻撃
6秒間20%減速
6秒間40%減速
60%ダウン
60%アップ
60.0%アップ
60.0%アップ
60%
65%アップ
70%
70%以下
8回攻撃
8.0%回復
8秒間味方艦
8.0%アップ
8秒間対象
9回攻撃
ちょっと、「あれ?」な感じは残るけど、おおむねいい感じの結果になった。
※辞書順と数値順を両立した感じ。
0.6アップ耐久
1.0%アップ同じ種類
1アップ耐久
1.2%回復
10秒毎重巡級
10秒毎40.0%発動8秒間自身
10.0%アップ
10.0%アップ同じ種類
10攻撃
10.0%回復
10.0%回復エンタープライズ
10.0%装填・命中
10%アップ
10%アップ魚雷クリティカルダメージ
10.0%アップ
10%ダウン
10.0%ダウン
10.0%回避
10.0%軽減
12回攻撃
12.0%アップ
15.0%アップ同じスキル
抽出語に複数の数値表現がある?
結果を見ると、数値表現が2か所以上でてくる抽出語がある。
そういう対応したいなと。