【JavaScript】配列:文字列と数値が混合している要素の並び替え

2 min read読了の目安(約1800字

以下の配列がある。奇数日がただバラバラに並んでいる文字列配列。

const odd_days = [
['1日'],['3日'],['13日'],['5日'],['9日'],['11日'],['7日'],['15日'],['17日'],
]

日付がちゃんと昇順に並ぶようにしたい。

しかしsort()を使って並び替えても、sort()はデフォルトでは昇順かつ文字列でソートするから、「1日」と「11日」では11日の方が先に並ぶ。

odd_days.sort()

// odd_daysの中身
// [["11日"],["13日"],["15日"],["17日"],["1日"],["3日"],["5日"],["7日"],["9日"]]

やったこと

sort()は引数に比較関数を指定することができるため、比較関数とparseInt()を組みこむことで解決。

配列のそれぞれの要素の先頭を元に並び替えるので、parseInt()を使って数値に変更。これで2桁以上の数値も取得できる。
1番目の要素から順番に要素の中身を比較関数で比較していく。

function compare(a,b){
    let index = 0
    let a_num = parseInt(a)
    let b_num = parseInt(b)

    if (a_num > b_num) {
        index = 1
    }else if (a_num < b_num) {
        index = -1
    }
    return index
}

const odd_days = [
['1日'],['3日'],['13日'],['5日'],['9日'],['11日'],['7日'],['15日'],['17日'],
]
odd_days.sort(compare)

// odd_daysの中身が日付の昇順にソートされる
// [["1日"],["3日"],["5日"],["7日"],["9日"],["11日"],["13日"],["15日"],["17日"]]

公式ドキュメントにも詳しく書かれてあるが、比較関数(今回はcompore(a,b))の返り値が
0未満の場合、aがbより先に並ぶ=a,bの順に並ぶ
0の場合、aとbはそのまま=a,bの順に並ぶ
0以上の場合、bがaより先に並ぶ=b,aの順に並ぶ(順序が入れ替わる)

今回定義した比較関数compore(a,b)では、まず配列の要素をそれぞれparseInt()で数値に変換。その変換した数値a_numb_numの大小を比較し、a_numの方が大きい時だけ配列の要素を入れ替えている。parseInt()で変換しているので2桁以上の数値も含めて昇順にソートできる。

実装満たせたのでリファクタしてみる

ちなみにcompare(a,b)の中身は以下のようにリファクタリングできる。比較関数の返り値のしくみが分かればこのコードも理解できるはず。

function compare(a,b){
    return parseInt(a) - parseInt(b)
}

さらにアロー関数を使うと関数定義もいらない。

odd_days.sort((a,b) => parseInt(a) - parseInt(b))

所感

いざ実装してみると実にシンプル。
調べても中々出てこなかったのでメモ。

参考

https://www.webprofessional.jp/sort-an-array-of-objects-in-javascript/
sort()と比較関数
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
parseInt()
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseInt