⚖️

セル名(A6, CA4とか)をJSでサクッとソートしたい

2022/06/13に公開

A1からzを描くようにソートしたい

つまり、どうにかしてこいつを

['A9', 'CA7', 'A4', 'B7', 'AB4']

こう並び替えたい

['A4', 'AB4', 'B7', 'CA7', 'A9']

行で並び替えは簡単

数字部分を抜き取って比較しちゃいましょう

const rowNumber = (str) =>  parseInt(str.replace(/\D/g, ''))
const sortedList = ['A9', 'A4', 'B7', 'AB4']
  .sort((a,b) => rowNumber(a) - rowNumber(b))
// → ['A4', 'AB4', 'CA7', 'B7', 'A9']

でもこれじゃあ行が同じ時に並び替えられないよ!!!!!!!

行が同じなら、列で並び替えれば良いじゃない
マリーアントワネット

文字列部分の並び替えも実は簡単

0~z までの36進数として考えるとサクッといけちゃいます

const columnNumber = (str) => parseInt(str.replace(/\d/g, ''), 36)
const sortedList = ['AZ', 'A', 'TAS', 'BF', 'C']
  .sort((a,b) => columnNumber(a) - columnNumber(b))
// → ['A', 'C', 'AZ', 'BF', 'TAS']

parseIntの第二引数には基数を設定できる(2~36の範囲で)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseInt

というわけで

const rowNumber = (str) => parseInt(str.replace(/\D/g, ''))
const columnNumber = (str) => parseInt(str.replace(/\d/g, ''), 36)
const sortCellString = (list) => {
  return list
    .sort((a,b) => {
      const rowDiff = rowNumber(a) - rowNumber(b)
      if (rowDiff === 0) {
        return columnNumber(a) - columnNumber(b)
      } else {
        return rowDiff
      }
    })
}
sortCellString(['A9', 'CA7', 'A4', 'B7', 'AB4'])
// → ['A4', 'AB4', 'B7', 'CA7', 'A9']

めでたしめでたし

雑談

これが必要な要件ってそんなに無いけど、ごく稀にあって、他で忙しかったりすると特殊なアルゴリズム考えたりしちゃうよねって思いからこの記事を書きました(というか引き継ぎでそういうコードに遭遇しました)

そして、parseIntのMDNしっかり読むと結構変な挙動するんですね....

締め切りに追われるエンジニアのみんな、一緒に頑張ろう!

Discussion