本記事ではfindメソッドとfindIndexメソッドについて解説していきます。
YouTubeでも解説していますので動画で見たい方は以下からどうぞ。
findメソッドの概要
findメソッドは、配列の要素を検索し、条件を満たす最初の要素を取得するための高階関数です。
たとえば以下のようなオブジェクトの配列があるとします。
const users = [
{ id: 'U001', name: '佐藤' },
{ id: 'U002', name: '鈴木' },
{ id: 'U003', name: '高橋' },
];
この配列の中から、「U001」というユーザーIDを持ったユーザーオブジェクトを抽出したいとき、以下のようにfindメソッドを使います。
function myFunction() {
const users = [
{ id: 'U001', name: '佐藤' },
{ id: 'U002', name: '鈴木' },
{ id: 'U003', name: '高橋' },
];
const targetUser = users.find(user => user.id == 'U001');
console.log(targetUser);
}
こちらの実行結果は以下の通りです。

IDがU001のオブジェクトを取得できました。
findメソッドの特徴
findメソッドの返り値は配列ではなく1個の要素が返ってきます。
これに関してはfilterメソッドと比較するとわかりやすいです。
IDがU001のユーザーオブジェクトを取得したいとき、findではなくfilterを使って抽出することもできます。
function myFunction() {
const users = [
{ id: 'U001', name: '佐藤' },
{ id: 'U002', name: '鈴木' },
{ id: 'U003', name: '高橋' },
];
const targetUser = users.filter(user => user.id == 'U001');
console.log(targetUser);
}
このようにfindを使わずfilterでもターゲットとなるユーザーを取得できます。
ただし、この場合取得されるデータは配列の形式となります。

したがって、filterを使ってターゲットとなるユーザーオブジェクトを取得したい場合は、最後に[0]
をつける必要があります。

一方findメソッドであれば、返り値は配列ではなく1個の要素が返ってくるので、[0]
をつける必要はありません。

つまり、以下の2つは同義・同値であるということですね。
users.filter(user => user.id == 'U001')[0];
users.find(user => user.id == 'U001');
これら2つは同義・同値ですが、この例のようにユニークなIDで配列の中から1個のデータを取得する場合は、基本的にfindを使うべきでしょう。
filterは配列のすべての要素をループさせる一方で、findは条件となる要素が見つかった時点でループが終了します。その分処理速度はfindの方が速くなるので、上記のようなケースではfindを使うことが推奨されます。
findとよく似たfindIndexメソッド
findメソッドとよく似たfindIndexメソッドという高階関数があります。
これは、配列の中から条件に一致する要素のインデックス番号を取得するメソッドです。
たとえば以下は、配列usersの中から、U003というIDを持つユーザーオブジェクトが何番目にあるのかを取得します。
function myFunction() {
const users = [
{ id: 'U001', name: '佐藤' },
{ id: 'U002', name: '鈴木' },
{ id: 'U003', name: '高橋' },
];
const targetIndex = users.findIndex(user => user.id == 'U003');
console.log(targetIndex);
}
こちらの実行結果は以下の通り。

U003のインデックス番号「2」が返ってきました。これはインデックス番号なので、0始まりの番号が返ってくることに要注意ですね。
find, findIndexの使用例
findで外部テーブルのデータを取得する
たとえば以下のように、2つのオブジェクトの配列users
とcities
があるとします。
const users = [
{ id: 'U001', name: '佐藤', city_id: 'C003' },
{ id: 'U002', name: '鈴木', city_id: 'C001' },
{ id: 'U003', name: '高橋', city_id: 'C002' },
];
const cities = [
{ id: 'C001', name: '東京' },
{ id: 'C002', name: '大阪' },
{ id: 'C003', name: '福岡' },
];
この2つの配列はリレーショナルデータベース(RDB)から持ってきたデータで、usersテーブルに関しては、外部キーとしてcity_id
を持っているというような場面を想定しています。
このとき、users
に関するfor文の中で、userオブジェクトのcity_id
をフックにしてcities
から該当のcityオブジェクトを取得するスクリプトが以下です。
function myFunction() {
const users = [
{ id: 'U001', name: '佐藤', city_id: 'C003' },
{ id: 'U002', name: '鈴木', city_id: 'C001' },
{ id: 'U003', name: '高橋', city_id: 'C002' },
];
const cities = [
{ id: 'C001', name: '東京' },
{ id: 'C002', name: '大阪' },
{ id: 'C003', name: '福岡' },
];
for (const user of users) {
const city = cities.find(city => city.id == user.city_id);
console.log(`${user.name}さんは${city.name}に住んでいます`);
}
}
こちらの実行結果は以下の通り。

このように、RDBにおいて外部テーブルのデータを取得するような場面でfindを使うことが個人的には多いです。
findIndexでシートの行数を特定する
たとえば以下のような顧客名簿のシートがあるとします。

このとき、U005の行数「6」を特定したい場合を考えます。

このとき以下のようにfindIndexを使うことで行数を求めることができます。
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Users');
const values = sheet.getDataRange().getValues();
const targetRow = values.findIndex(value => value[0] == 'U005') + 1;
console.log(targetRow);
}
findIndexで返ってくるのはインデックス番号である一方で、シートの行数は1から始まる番号なので、「+1」してあげることがポイントですね。
こちらの実行結果は以下の通り。

ターゲットとなる行数を求めることができました。
まとめ
以上、findメソッドおよびfindIndexメソッドについて解説しました。
この高階関数シリーズを最初から学習してきた人にとっては、これらはそんなに難しくないのではないでしょうか?
特に、第3回のfilterメソッドについてしっかり理解できていれば、今回のfindは簡単に習得できるはずです。
filterとfind、これら2つの違いに着目して、理解の解像度を高めましょう。
連載目次: 高階関数シリーズ
- 【高階関数】forEachメソッドについて解説 (GAS/JavaScript)
- 【高階関数】mapメソッドについて解説 (GAS/JavaScript)
- 【高階関数】filterメソッドについて解説 (GAS/JavaScript)
- 【高階関数】sortメソッドについて解説 (GAS/JavaScript)
- 【高階関数】reduceメソッドについて解説 (GAS/JavaScript)
- 【高階関数】findとfindIndexについて解説 (GAS/JavaScript)
- 【高階関数】everyとsomeについて解説 (GAS/JavaScript)
- 関数宣言・関数式・アロー関数 (GAS/JavaScript)
コメント