【JavaScript入門】初心者必見!配列操作を1行で書ける便利関数!(forEach/map/filter)

f:id:mido_app:20181007184623p:plain

こんにちは、みどーです。

プログラムを書いていると配列の各要素に〇〇する、という処理がよく出てきますよね。

そんなとき、初心者の方はfor文を回して書くことが多いのではないでしょうか。

この記事ではfor文よりも短く簡潔に配列を書き換えることができる便利な関数(forEach/map/filter)について解説します。

目次

対象読者

JavaScriptの初心者で、「配列の各要素に〇〇をする処理」をfor文を使って書いている方に向けて書いています。

なお、本文中にラムダ式(() => console.log('Hello world!')のような書き方)が出てきます。

この記事はラムダ式を知らない方でも読めるようになっていますが、ラムダ式を使った方が関数を短く簡潔に書けるようになりメリットが大きいです。

ラムダ式については以下の記事で初心者向けに解説しています。「ラムダ式わからないー!」という方は5分くらいで読めるのでよろしければ見てみてください。 www.midolog.net

この記事を読むことでできるようになること

便利な関数を3つ覚えて、for文と比べてめちゃくちゃ短い記述(1行)で配列操作ができるようになります。

早速便利な関数を見ていきましょう!

各要素に繰り返し処理をする "forEach"

まず1つ目の関数はfor文と同じように、配列の各要素に任意の処理を実行できる関数forEachです。

「配列の各要素をコンソールに出力する」処理を書きながら、for文とforEach関数それぞれの書き方を見てみましょう。

let array = [1, 2, 3]

// for文ver
for (let i=0; i<array.length; i++) {
  console.log(array[i])
}

// forEach ver
array.forEach(function (e) {
  console.log(e)
})

// forEach ラムダ式 ver
array.forEach(e => console.log(e))

for文の場合はarray[i]のように書くことで配列の要素にアクセスしています。

一方、forEachでは引数で渡した関数に、配列の各要素が渡ってきてそれを元に処理を行います。

例の中ではeという引数に配列の要素(1, 2, 3)が順番に渡ってきて、それをconsole.logでコンソールに出力しています。

ラムダ式を使うと、同じ処理でも1行にまとめて書くことができていますね!

各要素を変換する関数 "map"

2つ目の関数は、配列の各要素を別の値に変換するmapです。

どんな処理でも書くことができるforEachとは違って、変換することだけがmapのお仕事です。

配列.map(変換用の関数)のように使うと、変換した結果を新しい配列に入れて戻り値として返してくれます。

例として、配列の各要素を2倍にする処理を書いてみます。

let array = [ 1, 2, 3 ]

// for文 ver
let result = []
for (let i=0; i<array.length; i++) {
  result.push(array[i] * 2)
}

// map ver
let result = array.map(function (e) {
  return e * 2
})

// map ラムダ式 ver
let result = array.map(e => e * 2)

どのやり方もresultという変数に変換後の配列(要素を2倍したもの)が入ります。

mapの例では、eという引数に配列の要素(1, 2, 3)が順番に渡ってきて、それを2倍にしてreturnしているので、新しい配列の要素はもとの配列の2倍の値になります。

処理のイメージを簡単に図にするとこんな感じになります。

f:id:mido_app:20181010235902p:plain

ラムダ式で書くと矢印の左側を矢印の右に変換する、というイメージで直感的に書くことができます。上記の例の場合は、e => e * 2だから2倍になりますし、e => e * eなら2乗になります。

条件に合う要素だけ抜き出す関数 "filter"

最後の関数は、条件に合う要素だけを抜き出すための関数filterです。

mapと同様に、もともとの配列には変化を加えずに、要素を抽出した新しい配列を戻り値として返します。

配列.filter(抽出用関数)とすると、抽出用関数の戻り値がtrueの要素だけ抜き出された新しい配列を作ります。

言葉だけでは難しいので、例として偶数の要素だけを抜き出す処理を見てみましょう。

let array = [ 1, 2, 3, 4, 5]

// for文 ver
let result = []
for (let i=0; i<array.length; i++) {
  if (array[i] % 2 === 0) {
    result.push(array[i])
  }
}

// filter ver
let result = array.filter(function (e) {
  return e % 2 === 0
})

// filter ラムダ式 ver
let result = array.filter(e => e % 2 === 0)

上記のどのやり方でも、resultという変数に偶数のみ抜き出した配列([2, 4])が入ります。

filterの例では、配列の各要素が関数の引数eに渡ってきて、2で割った余りが0になる要素だけが抜き出されてresultの配列に入ります。

図にしてみると以下のようなイメージ。図の右側で点線になっている要素は、判定結果がfalseなのでresultの要素には含まれません。

f:id:mido_app:20181011003341p:plain

ラムダ式を使うと矢印の右側に残したい要素がtrue、残したくない要素がfalseになるような判定式だけを考えて書けばいいので非常に直感的です。

関数を繋げて複雑な処理を実現する

mapfilterは戻り値として配列を返すので、連続して書くことができます。

このようにメソッドを複数並べて書くことをメソッドチェーンといいます。鎖のようにメソッドが連続して並んでるイメージですね!

ひとつのmapで複雑な変換をするより、単純な変換をするmapを複数並べたほうが直感的で読みやすいコードになります。

例えば以下の例では、要素を2倍してから4を足す操作をメソッドチェーンを使って実装した例です。

let array = [ 1, 2 ,3 ,4 ,5]

let result = array.map(e => e * 2) // 2倍して
                  .map(e => e + 4) // 4足す

console.log(result) // [ 6, 8, 10, 12, 14 ]

また、ひとつの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歳未満を抜き出す

console.log(result) // 花子と里美だけの配列ができる

mapとfilterを混ぜることもできます。

例えば以下の例では、ユーザうち苗字が「田中」である人のフルネームの一覧を取得しています。

let users = [
  { lastname: '田中', firstname: '太郎' },
  { lastname: '田中', firstname: '花子' },
  { lastname: '高橋', firstname: '国子' },
  { lastname: '松井', firstname: '里美' }
]

let fullnameList = users.filter(user => user.lastname === '田中') // 田中のみ抜き出す
                        .map(user => user.lastname + user.firstname) // フルネームに変換

console.log(fullnameList) // [ ' 田中太朗', '田中花子' ]

おわりに

今回は1行で簡単に配列操作できる関数を3つ紹介しました。

場面に応じて使い分けられると、簡潔な表現になってソースコードがスッキリします。

私は仕事でもプライベートでもJavaScriptを書いていますが、慣れてくるともう繰り返しの処理でfor文を使うのはどうしても必要な時だけで、ほとんどこれらの関数を使って書いちゃいます。

ぜひ、使いこなせるように練習してみてください!