sortメソッドで文字列を任意の順番でソート


JavaScriptのsortメソッドでは配列の数値を並び替えることができますが、配列の文字列の並び替えもできます。

まずは配列が数値だけの場合です。

const suji = [50, 10, 100];
console.log(suji.sort()); // [ 10, 100, 50 ]

単純に配列にsort()メソッドを使うと、配列内の文字列が文字コード順に並び替えられています。もちろん、この文字コード順の並び替えで問題ないのなら、このままでいいです。

しかし、数値順に並び変えるのなら、以下のように比較関数にします。これで、数値の大きさ順に配列が並び替えられています。

const suji = [50, 10, 100];
console.log(suji.sort(function(x, y) {
	return x - y;
})); //  [ 10, 50, 100 ]

ここでしていることは、最初は50 - 10をして正数が返るから50は10より後で、50 - 100では負数が返るから50は100より前に来るというようにしているだけです。それを配列内の値で、順々に関数のxとyの引数に渡して位置を並び替えています。

実際に、並び替え後では、50は10より後で100より前の位置にきています。プログラムというと難しく聞こえますが、実際には、こんな小学校の算数の引き算程度でできることはかなりあります。

それでは、配列内の個々のオブジェクトの文字列を任意の順番で並び替える場合です。

const jyunban = ['人類', '第二の人類', '光る人', '火星人', '水の人'];

const taiyokei = [
  { namae: '水星', jyunin: '水の人' },
  { namae: '金星', jyunin: '光る人' },
  { namae: '地球', jyunin: '人類' },
  { namae: '火星', jyunin: '火星人' },
  { namae: '木星', jyunin: '第二の人類' },
];

console.log(taiyokei.sort(function(x, y) {
  return jyunban.indexOf(x.jyunin) - jyunban.indexOf(y.jyunin);
}));

ここでしていることは、taiyokeiの配列内オブジェクトの順番を配列のjyunbanの位置で並び替えています。実際に、並び替えた結果でコンソール画面に出るのが以下です。

0: Object { namae: "地球", jyunin: "人類" }

1: Object { namae: "木星", jyunin: "第二の人類" }

2: Object { namae: "金星", jyunin: "光る人" }

3: Object { namae: "火星", jyunin: "火星人" }

4: Object { namae: "水星", jyunin: "水の人" }

length: 5

このsort関数の内部で何が起こっているかを詳しく見てみます。

const jyunban = ['人類', '第二の人類', '光る人', '火星人', '水の人'];

const taiyokei = [
  { namae: '水星', jyunin: '水の人' },
  { namae: '金星', jyunin: '光る人' },
  { namae: '地球', jyunin: '人類' },
  { namae: '火星', jyunin: '火星人' },
  { namae: '木星', jyunin: '第二の人類' },
];

console.log('水の人 : ' + jyunban.indexOf(taiyokei[0].jyunin)); // 4

console.log('光る人 : ' + jyunban.indexOf(taiyokei[1].jyunin)); // 2

console.log('人類 : ' + jyunban.indexOf(taiyokei[2].jyunin)); // 0 

console.log('火星人 : ' + jyunban.indexOf(taiyokei[3].jyunin)); // 3

console.log('第二の人類 : ' + jyunban.indexOf(taiyokei[4].jyunin)); // 1

最初の{ namae: '水星', jyunin: '水の人' }のオブジェクトでは、jyunbanの配列の位置を見て、4が返っています。配列のjyunbanの水の人の位置は4です。しかし、taiyokeiの{ namae: '水星', jyunin: '水の人' }の配列内オブジェクトでの配列の位置は0です。これを並び替えるわけです。

光る人では2が返っています。水の人の4から光る人の2を引いて正数が返っているので、水の人のほうが光る人よりも後の位置に並び替えられます。

そして、以下のsort関数で、並び替えています。

console.log(taiyokei.sort(function(x, y) {
  return jyunban.indexOf(x.jyunin) - jyunban.indexOf(y.jyunin);
}))

つまり、していることは、数値で並び替えた場合の小学校の算数の引き算と同じです。配列内オブジェクトになって、文字列で難しそうに見えますが、jyunban配列の0,1,2,3,4の位置を見て算数の引き算をしているだけです。

console.log('水の人 : ' + jyunban.indexOf(taiyokei[0].jyunin)); のように、実際にsort関数の数値で何が起こっているかを確認するには、sort関数で並び替えをする前にしないと、並び替えた後では、並び替え後の数値が返って分からなくなります。

console.log(taiyokei.sort(function(x, y) {
  return jyunban.indexOf(x.jyunin) - jyunban.indexOf(y.jyunin);
}))

この後で

console.log('水の人 : ' + jyunban.indexOf(taiyokei[0].jyunin)); を実行すると、0になります。並び替えた後では、0: Object { namae: "地球", jyunin: "人類" }になっているので、人類のjyunban配列の位置を見て、0を返してきます。

プログラムは上から順番に評価されていくという基本的なことを忘れて、プログラムの間違いに気づかないで、どこにミスがあるのか分からなくなり時間が過ぎていくことがあります。

この場合は、console.log('水の人 : ' );のように、分かりやすく記述していることで、プログラムの順次評価でミスが起きた時に、かえって、分かりにくくなっています。