In 'n' Out

知識を取り込み、そして発信する

比較関数

比較関数

比較関数は、配列を並び替える際に、どの要素を前にするかを判断するための関数です。
配列のメソッドの中で使用した比較関数について改めて見てみましょう。

前出のコード例

//arraySort2.js
const arr = [1, 22, 133, 5, 2];

arr.sort();
alert(arr);
       
arr.reverse();
alert(arr);

比較関数を使わなかったため、文字列での並べ替えが行われ、結果は1,133,2,22,5でした。
大多数の方が小さい順に1,2,5,22,133と並べる方が自然だと思うのではないでしょうか。
その希望通りにするのがsortメソッド専用の比較関数です。

構文

//基本形
配列.sort(function(a, b) {
    return 比較結果;
});
//アロー関数形
配列.sort((a, b) => {
    return 比較結果;
});

配列の中から2つの要素を受け取り、その結果を数値として返す関数です。
sortメソッドは、配列の中から2つの要素を選び、それらを比較関数の引数aとbに渡します。
aとbは、配列の中から選ばれた2つの要素を一時的に受け取るための変数です。
イメージがしにくいため、いったんif文で置き換えた形で見てみましょう。

コード例

//compare1.js
const arr = [1, 22, 133, 5, 2];

function compare(a, b) {
  if (a < b) {
    return -1;
  }
  if (a > b) {
    return 1;
  }
  return 0;
}
       
arr.sort(compare);
alert(arr);

動作例

※このボタンは動作確認用です

こちらのコード例を実行すると、1, 2, 5, 22, 133 と数値が小さい順に並びます。
配列のsortメソッドは、配列の中から2つの要素を取り出し、それらを比較関数の引数aとbに渡します。
比較関数が返す数値が負の値の場合はaを前に、正の値の場合はbを前に並べます。
0の場合は順序を変えません。
今回のコードでは、a < b のときに-1を返すため、小さい数が前に並ぶ(昇順)結果になります。
sortメソッドは内部で要素の組み合わせを自動的に選び、その都度比較関数を実行し、返された値を元に並べ替えを行います。
例えば、22は1より大きいため1の右に並び、5は22より小さいため22の左に並ぶ、という判断が行われます。
ただし、扱う配列の要素は左から順に処理されるわけではなく、sortメソッド内部の仕組みによって自動的に扱われます。

このコードを比較関数にすると以下のようになります。

//compare2.js
const arr = [1, 22, 133, 5, 2];

arr.sort((a, b) => a - b);
alert(arr);

動作例

※このボタンは動作確認用です

a - bと書く比較関数は、先ほどif文で書いた比較関数とまったく同じ役割をしています。
a - bという書き方は、aとbの差をそのまま戻り値として返しています。
aがbより小さい場合、a - bは負の値になり、aがbより大きい場合、a - bは正の値になり、aとbが同じ場合、a - bは0になります。
これは、if文で書いた比較関数が返していた値と同じ条件です。
つまり、次の if文による比較処理を、if (a < b) return -1;、if (a > b) return 1;、return 0;となり、数値の計算に置き換えたものが、a - bという書き方です。
数値の並び替えでは、小さい数が前・大きい数が後という判定を差の正負だけで表現できるため、a - bという書き方がよく使われます。
ただし、これは数値の配列に限った書き方であり、文字列やオブジェクトの並び替えではif文による比較が必要になります。

a - bは新しいルールではなく、if文で書いた比較処理を1行で表した省略形です。
それでは、降順にするにはどうすればいいでしょうか。
コード例を見てみましょう。

//compare3.js
const arr = [1, 22, 133, 5, 2];

arr.sort((a, b) => b - a);
alert(arr);

動作例

※このボタンは動作確認用です

降順にしたい場合は、昇順で並べたあとにreverseを使うのではなく、比較関数をb - aと書くことで、最初から降順に並べることができます。

文字列の並べ替え

数値の並び替えでは a - bを使いましたが、文字列、特に日本語では同じ方法は使えません。
前出の文字列の並び替えを改めて見てみましょう。

前出のコード例

//arraySort1.js
const arr = ['メロン', 'りんご', 'みかん', 'いちご', 'ぶどう'];

arr.sort();
alert(arr);
       
arr.reverse();
alert(arr);

こちらの結果はいちご,ぶどう,みかん,りんご,メロンという並び替えがされました。
大多数の方が五十音順にいちご,ぶどう,みかん,メロン,りんごと並ぶ方が自然だと思うのではないでしょうか。
数値と同じく、文字列同士も < や > を使って比較することはできます。
この場合、内部的には文字コードの順番で比較されます。
しかし、必ずしも五十音順になるとは限りませんし、事実五十音順に並びませんでした。
そこで使用するのがlocaleCompareです。

構文

//基本形
配列.sort(function(a, b) {
    return a.localeCompare(b);
});
//アロー関数
配列.sort((a, b) => {
    return a.localeCompare(b);
});

localeCompareはメソッドで、文字列同士を比較し、並び替えに使える数値を返します。
日本語では五十音順になるように判定してくれます。

コード例

//compareString.js
const arr = ['メロン', 'りんご', 'みかん', 'いちご', 'ぶどう'];

arr.sort((a, b) => {
    return a.localeCompare(b)
});
alert(arr);

動作例

※このボタンは動作確認用です

数値でも文字列でも、比較関数が返す値の意味は同じです。
比較関数は「並び替えのルール」を決める関数です。
データの種類によって、比較の方法が変わるだけで、sortメソッドの仕組み自体は同じです。