【GAS】sortメソッドの使い方(配列の並べ替え)
Google Apps Script(GAS)で配列の並べ替えを行うにはsortメソッドを使います。
sortメソッドはデフォルトの並び替え法則と期待する並び替えが異なることがあるため注意が必要です。思い通りに並べ替えを行うには自分で並べ替え定義した関数を記述しなければなりません。この記事ではsortメソッドと関数の記述方法に理解を深めるための構文や仕様について紹介を行います。
手っ取り早く並べ替えの記述方法が知りたい方は下記の記事をご覧ください。
sortメソッドとは
配列の順序を並び替えるメソッドです。デフォルトだと文字列の順序で昇順に並び替えられますが、関数を定義することで並び替え順序を規定できます。
sortメソッドは変更メソッドのため、適応することで元の配列は変更されます。
sortメソッドの基本構文
Array.sort([func])
- func(任意):順列定義を関数として作成して適応可能。指定しなければ文字列昇順。※詳細後述
- 戻り値:並び替え後の配列
let animal = ['cat', 'dog', 'elephant', 'tiger', 'lion', 'monkey'];
console.log(animal.sort()); //[ 'cat', 'dog', 'elephant', 'lion', 'monkey', 'tiger' ]
let numbers = [6,9,2,3,1];
console.log(numbers.sort()); //[ 1, 2, 3, 6, 9 ]
デフォルトでは文字列の順序で並べ替えが実行される
まずは下記の例をご覧ください。
let numbers_2 = [6,90,20,3,10];
console.log(numbers_2.sort()); //[ 10, 20, 3, 6, 90 ]
数字の昇順で並べたいため「3, 6, 10, 20, 90」で並んでほしいところですが、実際には「10, 20, 3, 6, 90」で並んでいます。これはsortメソッド適応時に、並び替えが実行される前に配列要素が一度文字列に変換されることが要因です。そのため、上記の例だと['6′, ’90’, ’20’, '3’, ’10’]の順序で並び替えられていることになります。
同様に、文字列以外のデータ型の要素だと意図した並びにならないことが起こります。
これは並び替えの関数を定義することで解決可能ですので、下記のような目的であれば関数を使った方が良いでしょう。関数の記述方法は後で詳しくご説明します。
- 配列を降順に並び替える
- 数字を並び替える
- オブジェクトを並び替える
- 文字列を特定の言語慣例によって並び替えたい場合(複数言語を含める場合など)
二次元配列にsort()した場合の挙動
多次元配列対して関数を定義せずにsortメソッドを使用した場合、配列の最も表層の要素のみ並び替えが実行され、下層の配列内の要素までは並べ替えは適応されません。
let animal_2 = [['elephant', 'tiger'], ['lion', 'monkey'], ['cat', 'chicken'], ['cat', 'dog']];
console.log(animal_2.sort());
// 並び順
// [ [ 'cat', 'chicken' ],
// [ 'cat', 'dog' ],
// [ 'elephant', 'tiger' ],
// [ 'lion', 'monkey' ] ]
sortメソッドは変更メソッド
sortメソッドは変更メソッドなので、ある配列でsortメソッドを呼び出すと、元の配列にも変更が適応されています。
let animal = ['cat', 'dog', 'elephant', 'tiger', 'lion', 'monkey'];
let sorted_animal = animal.sort();
//戻り値も、元の配列も順序は逆になる
console.log(animal); //[ 'cat', 'dog', 'elephant', 'lion', 'monkey', 'tiger' ]
console.log(sorted_animal); //[ 'cat', 'dog', 'elephant', 'lion', 'monkey', 'tiger' ]
//元の配列を参照している
// console.log(animal === sorted_animal); //true
//元の配列を参照しているので、片方に変更を加えるともう片方にも反映されている
sorted_animal.push('Hippopotamus');
console.log(animal); //[ 'cat','dog', 'elephant', 'lion', 'monkey', 'tiger', 'Hippopotamus']
console.log(sorted_animal); //[ 'cat','dog', 'elephant', 'lion', 'monkey', 'tiger', 'Hippopotamus']
sortメソッドの関数の記述方法
前述のとおり、sortメソッドは並び順を指定しなければ、文字列変換後の昇順として並び替えが実行されます。
文字列以外が含まれる配列であればそもそも想定していた並び順にできず困りますし、降順にするようなちょっとした操作も他のメソッドを組み合わせなければならず手間がかかります。sortメソッドにはこれらを解決できるように、並び順を関数で定義し採用することができます。
関数の記述ポイントは下記です。
- 引数は比較対象となる2つの値(va1 と val2)
- 2つの値を比較して条件分岐させる
- 各条件で戻り値が「正の値」「0」「負の値」となるように設定する
・戻り値 > 0:val2をval1の前に移動
・戻り値 < 0:val1をval2の前に移動
・戻り値 =0 :並び替えなし
下記は並びが降順となる関数を記述しています。
//降順に並び替える関数
function descOrder(val1, val2) {
if(val1 > val2){
return -1; //val1>val2の場合、val1をval2の前に配置
}else if(val1 < val2){
return 1; //val1<val2の場合、val1をval2の後に配置
}else{
return 0; //配置変更なし
}
}
let animal = ['monkey', 'lion', 'tiger', 'cat'];
console.log(animal.sort(descOrder)); // [ 'tiger', 'monkey', 'lion', 'cat' ]
また、昇順の関数も記述してみます。数字を文字列変換する工程が入っていないため、数字の配列に実行した際に前述のような違和感のある並びにはなっていないことがわかります。
//昇順に並び替える関数
function order(val1, val2) {
if(val1 > val2){
return 1; //val1>val2の場合、val2をval1の前に配置
}else if(val1 < val2){
return -1; //val1<val2の場合、val2をval1の後に配置
}else{
return 0; //配置変更なし
}
}
let numbers_2 = [6,90,20,3,10];
console.log(numbers_2.sort()); //[ 10, 20, 3, 6, 90 ]
console.log(numbers_2.sort(order)); //[ 3, 6, 10, 20, 90 ]
ちなみに、要は各条件で戻り値が「正の値」「0」「負の値」となるように記述すればよいので、下記のような形で記述しても問題ありません。
let numbers_2 = [6,90,20,3,10];
console.log(numbers_2.sort((a, b) => {return a - b;})); //[ 3, 6, 10, 20, 90 ]
2次元配列を指定列で並び替える
2次元配列と対応するのが、スプレッドシートから読み込んだデータです。スプレッドシートからデータを読み込むと行ごとの二次元配列として生成されるため、sortメソッドをそのまま呼び出してしまうと一列目を基準として並び替えが実行されることになります。
下記のようなスプレッドシートデータを処理すること想定します。普通にsortメソッドを呼び出すと先頭列の「商品」での並び替えが行われてしまいますが、例えば第4列目の「売上」で並び替えたい場合はどうすればよいでしょうか。
関数内の各行要素の比較条件分岐の際、要素のインデックス指定で第4要素(インデックス3)である売上を指定すればOKです。
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName('売上');
let range = sheet.getDataRange();
let values = range.getValues();
values.shift(); // 列名である第一要素を削除
function sortSales(a, b){
if (a[3] < b[3]) {
return 1;
} else if(a[3] > b[3]){
return -1;
}else{
return 0;
}
};
//書き込み
let outputSheet = ss.getSheetByName('並び替え後');
outputSheet.getRange(2,1,4,4).setValues(values.sort(sortSales));
うまく並び替えられました。
2次元配列を複数条件で並び替える
第二条件が発動するのは第一条件で値が等しかった場合なので、関数の条件分岐で2つの値が等値になった際に、別の要素番号での条件分岐を記述すればOKです。
前述と同じデータを例に、【第一条件:「個数」降順】→【第二条件「売上」降順】とする関数を記述します。
function sortUnitSales(a, b){
if (a[2] < b[2]) {
return 1;
} else if(a[2] > b[2]){
return -1;
}else{
if (a[3] < b[3]) {
return 1;
} else if(a[3] > b[3]){
return -1;
}else{
return 0;
}
}
};
//書き込み
let outputSheet = ss.getSheetByName('並び替え後');
outputSheet.getRange(2,1,4,4).setValues(values.sort(sortUnitSales));
うまく並び替えられました。
まとめ
配列の並び替えを行うsortメソッドについて詳細のご紹介を行いました。
- 基本構文はArray.sort([func])で記述できる
- 変更メソッドであり、呼び出し後に元の配列も変更される
- デフォルトでは文字列に変換後に並べ替えが実行される
- 並び替え法則を指定する関数を記述可能
- 二次元配列にて、第一要素以外での並べ替えや複数要素を指定してた並び替えもできる