JavaScriptでプログラムを書いていると「配列・リストの要素から条件に合うものを抽出したい!」という処理がよく出てきますよね。
そんなとき、初心者の方はfor文とif文を駆使して処理を書くことが多いのではないでしょうか。
この記事ではfor文・if文を使うよりも簡単に配列・リストの要素を絞り込むことができるfilter関数について解説します!
この記事を読み終わる頃には配列・リストの要素検索に便利なfilter関数を覚えて、for文・if文を使った場合と比べてめちゃくちゃ簡潔な記述(頑張れば1行!)で配列操作ができるようになります。
Table of Contents(目次)
対象読者
JavaScriptの初心者で、「配列・リストの要素から条件に合うものを抽出する処理」をfor文・if文を使って書いている方に向けて書いています。
なお、本文中にラムダ式(() => console.log('Hello world!')
のような書き方)が出てきます。
この記事はラムダ式を知らない方でも読めるようになっていますが、ラムダ式を使った方が関数を短く簡潔に書けるようになりメリットが大きいです。
ラムダ式については以下の記事で初心者向けに解説しています。「ラムダ式わからないー!」という方は5分くらいで読めるのでよろしければ見てみてください。
for文・if文を使って要素を抽出する場合
filter関数を使った場合と比較するためにまずはfor文/if文を使って配列・リストからの要素抽出処理を書いてみます。
例として「数値の入っている配列・リストから偶数の要素のみ抜き出す処理」は以下のようになります。
let numList = [ 1, 2, 3, 4, 5 ]
// for文/if文を使った場合
let resultList = []
for (let i=0; i<numList.length; i++) {
if (numList[i] % 2 === 0) {
resultList.push(numList[i])
}
}
for文・if文を使う場合、結果を保存するための配列を定義する必要があります(この例の場合はresultList)。
そして、for文を回しながら順番に各要素が条件に合うかをチェックして、条件に合うものを見つけたら結果の配列にpushするという流れです。
filter関数を使う場合
配列・リストから条件に合う要素をだけを抜き出すための便利な関数、それが”filter”関数です。
使い方としては、配列.filter(抽出用関数)
とすると、抽出用関数の戻り値がtrue
の要素だけ抜き出して新しい配列を作ります。
言葉だけでは難しいので、例として偶数の要素だけを抜き出す処理を見てみましょう。
以下のコードを実行するとresultListに偶数のみ抜き出した配列([2, 4]
)が入ります。
let numList = [ 1, 2, 3, 4, 5]
// filter関数を使った場合
let resultList = numList.filter(function (e) {
return e % 2 === 0
})
それではこのコードを順番に解説していきます。
まず、上記の例の中での抽出用関数は
function (e) {
return e % 2 === 0
}
という関数になっていますね。
これは、「引数eを受け取って偶数ならtrueを返す」関数になっています。
filter関数はこの抽出用関数の引数eに配列の各要素を順番に入れて呼び出していき、結果がtrueになった要素だけを残してくれる関数なのです!
図にしてみると以下のようなイメージです。図の右側で点線になっている要素は、抽出用関数の結果がfalse
なのでresultListの要素には含まれません。
また、for文・if文を使った場合とは違って、自分で結果用の配列を用意する必要がありません。抽出用関数の結果がtrueになる(=条件に合う)要素を抜き出して、新しい配列・リストにして返してくれるのです。
for文・if文の場合と比較するととても短く書けているのがわかると思います。
let numList = [ 1, 2, 3, 4, 5]
// for文/if文を使った場合
let resultList = []
for (let i=0; i<numList.length; i++) {
if (numList[i] % 2 === 0) {
resultList.push(numList[i])
}
}
// filter関数を使った場合
let resultList = numList.filter(function (e) {
return e % 2 === 0
})
ちなみに、抽出用関数の引数の名前は自分の好きに変えることができます。ここまでの例は配列の要素(=element)の頭文字eを引数の名前としていましたが、例えば「引数に渡されるのが数字だからnumにしよう!」というのもOKです。
// 引数の名前は自由
let resultList = numList.filter(function (num) {
return num % 2 === 0
})
filter関数を使った処理をもっと簡潔に書く方法
filter関数を使うととても簡単に要素を抽出できることがわかりました。でも、ラムダ式を使うとさらに簡潔に書くことができるんです。
let numList = [ 1, 2, 3, 4, 5]
// for文/if文を使った場合
let resultList = []
for (let i=0; i<numList.length; i++) {
if (numList[i] % 2 === 0) {
resultList.push(numList[i])
}
}
// filter関数を使った場合(通常版)
let resultList = numList.filter(function (e) {
return e % 2 === 0
})
// filter関数を使った場合(ラムダ式版)
let resultList = numList.filter(e => e % 2 === 0)
ラムダ式を使うと矢印の右側に残したい要素がtrue
、残したくない要素がfalse
になるような判定式だけを考えて書けばいいので非常に直感的になります。
説明すると長くなってしまうので、この記事ではラムダ式については詳しく説明しません。ラムダ式について詳しく知りたい方は以下の記事で丁寧に説明しているのでお時間があれば読んでみてください。
時間がない方は「ラムダ式を覚えたらもう少し短くかけるんだな」くらいに覚えておいてもらえればOKです。
filter関数を使って配列・リストから要素を抽出する例
例が1つだとイメージが湧かないかもしれないので、いくつかの例で実際に使ってみましょう。
例1: 奇数だけを抽出
let numList = [ 1, 2, 3, 4, 5]
// for文/if文を使った場合
let resultList = []
for (let i=0; i<numList.length; i++) {
if (numList[i] % 2 === 1) {
resultList.push(numList[i])
}
}
// filter関数を使った場合(通常版)
let resultList = numList.filter(function (e) {
return e % 2 === 1
})
// filter関数を使った場合(ラムダ式版)
let resultList = numList.filter(e => e % 2 === 1)
例2: 田中さんのみ抽出
let nameList = [
'田中太郎',
'鈴木一郎',
'田中花子'
]
// for文/if文を使った場合
let resultList = []
for (let i=0; i<nameList.length; i++) {
if (nameList[i].startsWith('田中')) {
resultList.push(nameList[i])
}
}
// filter関数を使った場合(通常版)
let resultList = nameList.filter(function (name) {
return name.startsWith('田中')
})
// filter関数を使った場合(ラムダ式版)
let result = nameList.filter(name => name.startsWith('田中'))
例3: 20代の人のみ抽出
let users = [
{ name: '太郎', age: 25 },
{ name: '花子', age: 27 },
{ name: '国子', age: 31 },
{ name: '里美', age: 21 }
]
// for文/if文を使った場合
let resultList = []
for (let i=0; i<users.length; i++) {
if (users[i].age >= 20 && users[i].age < 30) {
resultList.push(users[i])
}
}
// filter関数を使った場合(通常版)
let resultList = users.filter(function (user) {
return user.age >= 20 && user.age < 30
})
// filter関数を使った場合(ラムダ式版)
let result = users.filter(user => user.age >= 20 && user.age < 30)
filter関数で要素が何番目にあるかを抽出条件にしたい場合
冒頭で説明したように、filter関数は配列.filter(抽出用関数)
という形式です。
例えば、「filter関数を使って偶数番目にある要素だけ抜き出したい」のように抽出条件に要素の順番を入れたい場合、抽出用関数の第2引数に要素の番号が渡ってくるのでそれを使うことができます。
以下に偶数番目にある要素だけ抽出する例を示します。
注意として渡ってくる要素番号は0から始まります。偶数番目を取得する場合、要素番号(=例の中のi
)は0,1,2,3...
となるので2で割った余りが1の場合が偶数番目になります。
let numList = [ 1, 2, 3, 4, 5 ]
// for文/if文を使った場合
let resultList = []
for (let i=0; i<numList.length; i++) {
if (i % 2 == 1) {
resultList.push(numList[i])
}
}
// filter関数を使った場合(通常版)
let resultList = numList.filter(function (e, i) {
return i % 2 === 1
})
// filter関数を使った場合(ラムダ式版)
let resultList = numList.filter((e, i) => i % 2 === 1)
要素の順番を条件として使わない場合は第2引数は省略して書いてOKです。
filter関数を繋げて複雑な絞り込みを実現する
filter関数は戻り値として配列を返すので、連続してfilter関数を書くことができます。
このようにメソッドを複数並べて書くことをメソッドチェーンといいます。鎖のようにメソッドが連続して並んでるイメージですね!
ひとつのfilterで複雑な条件を指定をするより、単純な変換をするfilterを複数並べたほうが直感的で読みやすいコードになる場合があります。
例えば以下の例では、ユーザのリストから20代の女性を抜き出しています。
let users = [
{ name: '太郎', gender: '男', age: 25 },
{ name: '花子', gender: '女', age: 27 },
{ name: '国子', gender: '女', age: 31 },
{ name: '里美', gender: '女', age: 21 }
]
let result = users.filter(user => user.gender === '女') // 女性のみ抜き出す
.filter(user => user.age >= 20) // 20歳以上を抜き出す
.filter(user => user.age < 30) // 30歳未満を抜き出す
おわりに
今回は配列・リストの要素から条件に合うものを抽出する処理を簡潔に書けるfilter関数の紹介でした。
慣れないうちはfor文・if文との違いに頭を使うかもしれませんが、慣れてしまえば少ない行数で直感的なコードを書くことができます。
ぜひ、使いこなせるように練習してみてください!
また、今回紹介したfilter関数と似たような使い方で、配列・リストの要素を変換できるmap関数の解説記事も書いています。
両方マスターすることで要素の絞り込み・変換をfor文なしでとても簡単に書けるようになるので興味があればそちらもご覧ください。