[GAS, JavaScript] 脱初心者！配列の filter, map, find を使えるようになろう 

# これは何？

非エンジニア向けにGoogleAppsScript(GAS)レクチャーを行なっています。プログラムが全くの初めての人を対象にしています。このレクチャーを卒業し、基本的なことが理解できるようになった人が「その次に知っておいたほうがいいこと」の一つに **配列の扱い** があるなと思いました。これを説明してみよう、という記事。

実務でよく使いそうな、`filter`, `map`, `find` についてです。


# 対象者

* GoogleAppsScriptおよびJavaScriptでの基本構文は知っている
* 具体的には [ケーススタディでしっかり身につく! Google Apps Script超入門](https://www.amazon.co.jp/dp/4297126273) を修了している

* **アロー関数について理解できている** → まだの人は[私がアロー関数を理解するまで](https://qiita.com/sakaimo/items/678dc05105ecce3a642a)を先に読んでおいてください！




# [1] 配列の要素のうち特定の条件を満たすものだけを含む配列を作りたい (filter)

与えられた配列のうち、50以上の要素だけを抜き出したい(50以上の要素だけを持つ、新しい配列を生成したい)とします。


## まずはこういう書き方になりそう

[ケーススタディでしっかり身につく! Google Apps Script超入門](https://www.amazon.co.jp/dp/4297126273)に書かれている知識だけで処理しようとすると下記のようになります。

```js
function filter1() {
  // この配列の中から「50以上」の要素だけを取り出して新しい配列にしたい
  const numbers = [80, 40, 80, 30, 60];

  // 結果をいれるカラの配列を作って
  const result = [];

  // for文の中で条件に当てはまる要素を result に push する
  for (const number of numbers) {
    if (50 <= number) {
      result.push(number);
    }
  }

  // result は条件に当てはまるものだけが入った配列になる
  console.log(result);
}
```

```plaintext
[ 80, 80, 60 ]
```

## filterを使うとこうなる

```js
function filter2() {
  const numbers = [80, 40, 80, 30, 60];
  const result = numbers.filter(number => 50 <= number);
  console.log(result);
}
```

```plaintext
[ 80, 80, 60 ]
 ```

どうでしょうか。コード量がグっと減りましたね。

ただ、初めてこれを見たときに「...ん？」ってなりませんか？私はなりました。
`numbers.filter(number => 50 <= number)` ← ここね。

`=>` は「アロー関数」という書き方になりますが、ここがわかってない人は [私がアロー関数を理解するまで](https://qiita.com/sakaimo/items/678dc05105ecce3a642a) を読んでほしい！

```js:
  const result = numbers.filter(number => 50 <= number);
```

についてちょっと無理やり説明すると

```plaintext:
numbers.filter(number => 
```

の部分で
* `numbers`配列に対して `filter`をかけるよ、っていうのがわかる
* `numbers`配列から順番に1つずつ要素を取り出して(←ここにループの要素が含まれている)`number`という変数に代入するよ

という理解をしています。

さらに、「フィルタリングする条件」は何かというと

```plaintext:
50 <= number
```

であり、この条件を満たした要素を`result`配列に入れていく(`result`に`push`)

その結果として「フィルタリングの条件を満たす要素だけが入った`result`配列が生成される」になります。

```js:
  const result = numbers.filter(number => 50 <= number);
```

仕様として

* `filter`の戻り値は「配列」です
* この例だと `result` は`[ 80, 80, 60 ]`という配列になります
* フィルタリングの条件を満たす要素が1つもない場合は、空の配列 `[]`になります
* 元の配列(`numbers`)は変更されません


詳細について知りたい人はこちら→ [Array\.prototype\.filter\(\)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)



# [2] 配列の要素全てに対して何かの処理をして、新たな配列を作りたい (map)

例えば5人に100点満点のテストを受けてもらって、その結果があったとして、何らかの理由で「全員に+10点する」みたいな処理をしたいとします。

## まずはforで書くよね

```js
function mapFunc1() {
  const scores = [80, 40, 80, 30, 60];

  // 結果をいれるカラの配列を作っておいて、
  const result = [];

  // ループさせて各要素に対して+10の処理をして、result に push
  for(const score of scores){
    result.push(score+10);
  }

  // 結果として各要素が+10された配列ができあがる
  console.log(result);
}
```

```plaintext:実行結果
[ 90, 50, 90, 40, 70 ]
```

## mapを使うとこうなる

```js
function mapFunc2() {
  const scores = [80, 40, 80, 30, 60];

  const result = scores.map(score => score + 10);
  console.log(result); // [ 90, 50, 90, 40, 70 ]
}
```

```js
const result = scores.map(score => score + 10);
```
についての理解として
* `scores`配列に対して`map`の処理をするよ
* `scores`配列から1つ取り出した要素を`score`変数にいれるよ
* `score + 10` した結果を `result` に入れていく (`result`に`push`) よ

`map`は配列の「全て」の要素に対して、同じ処理をしたいときに使えます。

仕様として
* `map`の戻り値は配列です
* 元の配列(`scores`)は変更されません


詳細について知りたい人はこちら→ [Array\.prototype\.map\(\) \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map)


## mapの実践編

せっかくなので実務で使いそうなケースを考えてみます。
スプレッドシートでこんなデータがあるとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/986e6825-ef15-d1db-e2db-bb4b46cde701.png)

全ての人に対して「姓+名」の文字列を生成したい、みたいなケースってありそうですよね。

```js
function mapFunc3() {
  // スプレッドシートから取得したデータは2次元配列になっている
  const data = [
    ['田中', '太郎'],
    ['山本', '花子'],
    ['鈴木', '一郎'],
    ['高橋', '由美'],
    ['佐藤', '健太'],
    ['伊藤', '美咲'],
    ['渡辺', '大輔'],
    ['中村', '結衣'],
    ['小林', '拓海'],
    ['加藤', '杏奈']
  ];

  const result = data.map(row => row[0] + row[1]); // 文字列連結の'+'
  console.log(result);
}
```

```plaintext:実行結果
['田中太郎', '山本花子', '鈴木一郎', '高橋由美', '佐藤健太', '伊藤美咲', '渡辺大輔', '中村結', '小林拓海', '加藤杏奈']
  ```

どうでしょう？コードの中身は理解できますか？

今回は`data`が二次元配列なので

```
data.map(row => row[0] + row[1])
```

は「`data`から1つの要素を取り出して`row`変数にいれる」わけですが、このときの`row`は `[姓, 名]` という配列です。


# [3] 配列の要素のうち、条件を満たす要素を1つ取り出す (find)

`filter`と似ていますが「条件を満たす要素があったらその要素を取り出す」という処理です。

例えばあるクラスでテストを実施して、「名前」と「点数」のリストが存在する。
この中から特定の名前の人の情報を探したい。みたいな。


## まずはこういう書き方になるかな。

```js
function findFunc1() {
  const data = [
    { name: '田中太郎', score: 80 },
    { name: '山本花子', score: 40 },
    { name: '鈴木一郎', score: 80 },
    { name: '高橋由美', score: 30 },
    { name: '佐藤健太', score: 60 }
  ];

  const targetName = "鈴木一郎"; // この名前の人の情報を探したい

  // 結果を入れる変数
  let result;

  // forを回して一致する要素があれば result に入れて break する
  for(const member of data){
    if(member.name === targetName){
      result = member;
      break;
    }
  }

  console.log(result);
}
```

```plaintext
{ name: '鈴木一郎', score: 80 }
```

## findを使って書いてみる


```js
function findFunc2() {
  const data = [
    { name: '田中太郎', score: 80 },
    { name: '山本花子', score: 40 },
    { name: '鈴木一郎', score: 80 },
    { name: '高橋由美', score: 30 },
    { name: '佐藤健太', score: 60 }
  ];

  const targetName = "鈴木一郎"; // この名前の人の情報を探したい

  const result = data.find(member => member.name === targetName);
  console.log(result); // { name: '鈴木一郎', score: 80 }
}
```

```js
  const result = data.find(member => member.name === targetName);
```

* `data`に対して`find`を実行するよ
* `data`から1つ取り出して`member`変数にいれるよ
* `member.name === targetName` を満たす要素があったら `result` に代入するよ

という意味です。


仕様として

* 条件を満たす要素が存在しない場合は `undefind` を返します
* 条件を満たす要素が複数ある場合、条件を満たす最初の要素を返します

になります。`filter`は条件を満たす要素すべてを配列として返しますが、`find`は「最初に見つかった要素だけ」を返します。

詳細について知りたい人はこちら→[Array\.prototype\.find\(\) \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/find)


# おわりに

JavaScript、GASでは「配列を扱う便利な関数」がいっぱいあります。

[Array \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)で調べてみてください。

今回紹介した3つ以外では `concat`, `every`, `flat`, `includes`, `join`, `some` などがよく使いそうでしょうか。

**配列を操作するときには「自分で処理を考えるより先に、それをやってくれる関数を探す」のがいいと思います！**