配列の要素に対する処理には繰り返し構文よりも高階関数を使ってみよう

こんばんはimaizumeです。
プログラミングを勉強していると、どんな言語であっても必ず覚える構文ってありますよね :question: 
中でも繰り返し(for, while, until etc)はどんな言語でも必ず出てくる基本構文だと思います。

もし繰り返しの構文がある程度使えるようになったら、次はぜひ**mapやfilterといった高階関数を覚えてみましょう。**
この `map` や類似の `filter`, `reduce`といった関数は　**[高階関数](https://ja.wikipedia.org/wiki/%E9%AB%98%E9%9A%8E%E9%96%A2%E6%95%B0)と呼ばれ、配列の各要素に対してfor文等と同様繰り返し処理を行うためのものです**

(:warning: mapは本来**写像関数**といい、ある配列要素を別の要素に対応付けて変換するための関数一般を表す言葉です。よってreduceやfilterなどの他の高階関数も、**厳密には繰り返しと同一ではありません**が、この記事ではあくまで最初に覚えるときのニュアンスを伝えるために、繰り返しの場合と対応付けする形で説明しています。)


ただ同じ処理をしても、高階関数を使えば**for文に比べてコードが見やすくなる場合があります。**
また **要素への処理を関数にまとめて使い回しできたり、リファクタリングしやすくなったりする効果もあります** :exclamation:
慣れると大変便利なので、for文の使い方を覚えられたら、この記事を参考に `map`や`filter`にもチャレンジしてみてください。

解説の前に
---

### この記事の対象読者

* `map`とか`filter`を聞いたことがあるけれど使い方、使いどころがイマイチ分からない
* 配列の各要素に対して処理を行う部分をもっと簡潔に書きたい
* 配列に対する繰り返しで使う集計用変数を減らしたい
* 関数型プログラミングに興味がある

### mapなどの高階関数をサポートしている主な言語

サポートがある主要な言語は以下のとおりです。
(筆者が知見のある範囲を中心にした紹介ですので他の言語でもサポートされているものはたくさんあります)

* [JavaScript](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
* [Ruby](http://ref.xaio.jp/ruby/classes/array/map)
* [Python](http://docs.python.jp/2/library/functions.html#map)
* [R](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/24.html) (apply系関数)
* [Swift](https://developer.apple.com/reference/swift/sequence/1641260-map)
* Java ([RxJava](https://github.com/ReactiveX/RxJava)などのライブラリで利用可能)

なお**この記事ではJavaScriptを使って解説していきますが、基本的なmap関数の使い方はどの言語でも大体同じです**ので、適宜自分の言語に読み替えてください (JavaScriptを使う理由は単純にブラウザ上ですぐに実行が可能だからです)

基本的なmap関数の使い方
---

では、**高階関数の基本であるmap関数の使い方を見ていきます。**
例えばこんな感じの、配列の中身を出力する簡単なプログラムがあります。

```javascript:for.js
var x = [1,2,3];
for(var i=0; i < x.length; i++) {
  console.info(x[i]);
}
// 1
// 2
// 3
```

これをmapで書き直すと...

```javascript:map.js
var x = [1,2,3];
x.map(function(i){ console.info(i); });
// 1
// 2
// 3
```

どうでしょう、3行が1行になってちょっとスッキリしませんか :question: 
**このようにmap関数は、要素に対して行う処理を書いた関数を引数に与えてあげることで、for文同様配列内の各要素に対して同じ処理を繰り返し実行することができます。**
今の例では`function`内の処理は1行でしたが、もちろん複数行に渡る処理を記述しても構いません。

呼び出しのイメージはこんな感じ :arrow_down: 

![form-of-map.png](https://qiita-image-store.s3.amazonaws.com/0/17214/6b6f8398-4ccd-53d0-be33-b166e4c98456.png)

図中の青い矢印の方向に処理が進んでいくというイメージを持つと理解がしやすいと思います。
呼び出すとこのように各要素に対して順番に処理がなされていくわけです。

![form-of-map-example.png](https://qiita-image-store.s3.amazonaws.com/0/17214/16971b2b-a677-95b5-9b3b-7505b37d6c50.png)

以上がmap呼び出しの最も基本的な形になります。

結果を新しい配列に格納する
---

先程は配列内の値を出力しただけでした。
今度は**それぞれの処理結果を新しい配列として受け取りたい場合を考えます。**
例えばある配列の各要素の値を2倍し新しい配列として受け取りたい場合、for文を使うとこのようなコードになります。

```javascript:array_with_for.js
var x = [1,2,3];
var twice = []; // 事前に結果を受け取る変数を定義しておく
for (var i= 0; i<x.length; i++) {
  twice.push(x[i] * 2);
}
console.info(twice); // [2, 4, 6]
```

forだと事前に新しい配列を入れるための変数を作成しておく必要がありますが、このような場合はmap関数の恩恵を受けることができます。

```javascript:array_with_map.js
var x = [1,2,3];
var twice = x.map(function(i) { return i*2; });
console.info(twice); // [2, 4, 6];
```

このように、**mapは引数内のfunctionにて行った処理の結果を、そのまま配列にして返却してくれる** のです。
ただし先程と違い、**最終的に値を返却するために`return`を付けているのに注意してください**、これがないと新しい配列に値が戻りません。
関数内での処理を行ったうえで、最後に値を`return`することにより、新しい配列の要素を戻すことができるのです。
どうでしょうか、結構便利じゃないですか :question: 

`return`付きのmap関数の呼び出しは、イメージにするとこんな感じになります。

![form-of-map-return.png](https://qiita-image-store.s3.amazonaws.com/0/17214/ca4294b9-a195-a62f-22cb-c7b79683739f.png)

具体的な返り値を合わせたイメージはこのような感じ

![form-of-map-return-example.png](https://qiita-image-store.s3.amazonaws.com/0/17214/72c73f13-fff4-6caa-30ab-264047e97976.png)

関数を変数に入れる
---

『関数を変数に入れる』という表現には最初慣れないかもしれないですが、これも覚えておくとさらに便利にmapが使えます。
JavaScriptなどの言語では関数を定義した後、それをまるごと変数に入れて使い回すことができます。

```js
fx = function(x) { return x + 2; }
console.info(fx(1)); // 3
console.info(fx(3)); // 5
```

先ほどの例で出てきた値を2倍する関数も、一度変数に入れてから`map`に渡すことができます。
**あとで何度も同じfunction内の処理を使う場合などは、このように関数を変数に入れておくと使い回しができて良いです。**

```javascript:function_obj.js
var fx = function(x) { return x*2; }
console.info([1,2,3].map(fx)); // [2, 4, 6]
console.info([7,4,1].map(fx)); // [14, 8, 2]
console.info([-0.5,0,0.5].map(fx)); // [-1, 0, 1]
```

filter関数
---

`map`と似たような関数に**`filter`があります。**
これは**各要素に対して条件判定を行い、その判定結果がtrueであったものを返す関数です。**
まさに名前の通り、配列から特定の値だけを『フィルタリング』するときに使います。

例えば、配列から2より大きいの値のみを抜き出したいときはこんな感じに書いてあげます。

```javascript:filter_example.js
var x = [1,2,3];
console.info(x.filter(function(i) { return i > 2; })); // [3];
```

![form-of-filter.png](https://qiita-image-store.s3.amazonaws.com/0/17214/181bf8e9-f4e2-402a-01e2-7341bbc452a9.png)

function内では最終的に`true`か`false`が返れば良いので、その手間はもっと複雑な処理をしても構いません。
単純な評価であれば**if文すら不要になるためこちらも大変重宝します**。

![form-of-filter-example.png](https://qiita-image-store.s3.amazonaws.com/0/17214/f01f269b-8165-82ce-f0c4-21a115506c4b.png)


複数の関数を組み合わせる
---

高階関数のスゴい所は、ドットでつなげることで処理した結果をさらに続けて次の処理へ繋げられることです(メソッドチェーン)。

```javascript:multiple_maps.js
var fx = function(x) { return x * 10; } // 値を10倍
var gx = function(x) { return x > 15; } // 15より大きければtrueを返す
console.log([1,2,3].map(fx).filter(gx)); // [20, 30]
```

最初のうちはあまりメソッドチェーンを使う機会がないかもしれませんが、配列を加工する処理が複雑化してきたときにこの仕組みが役に立ちます。
**変数を経由しないでも連続的に処理を記述できるため、コードの中で見なければならない部分が減ることが重要です。**

map, filter以外の高階関数
---

最後に上記で紹介したmapとfilter以外の高階関数についても少しだけ紹介しておきます。

### forEach

冒頭の例で出たような新しい配列へと変換をしない (=中の関数が何も`return`しない) 場合は`forEach`の方が適切です。
使い方は`map`の場合と同じです。

```js
var x = [1, 2, 3];
x.forEach(function(value, index, array) { console.info(x); });
// 1
// 2
// 3
```

functionの引数が増えていますが、それぞれ配列の各要素、インデックス番号、参照している配列を参照するための変数です。

### reduce

**配列の中の値をまとめて1つの値を返したいような処理を行うための関数です。**
例えばこのようにforの外側に変数を作って値を集計するような場合

```javascript
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var sum = 0;
for(i=0; i<x.length; i++) {
  sum += x[i];
}
console.info(sum); // 55
```

reduceを使うとこんなにスッキリ書くことができます。

```javascript
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.info(x.reduce(function(prev, i){ return prev + i; })); // 55
```

mapやfilterと違い、**functionの引数が2つに増えていますが、それぞれ直前に返却した値(`prev`: forを使った場合のsumに相当する変数)と各要素の値(`i`)をとります。**
この関数は2番目の要素から適用され、`prev`の初期値は最初の要素の値になります。
そして集計をする場合は前の値に今の要素の値を足して返却していくだけで最後に集計値が返ります。

### every, some

`every`と`some`は`filter`に近い関数で、**全ての要素がfunction内でtrueを返せばtrue (=AND判定)、someは要素のうち1つでもtrueを返せばtrue (=OR判定)を返します**。

例えば配列の中の全ての要素が3以上であるかを判定するには`every`をこのように使います。

```javascript
var x = [2, 3, 4]
console.log(x.every(function(i){ return i >= 3; })); // false (2があるので)
var y = [4, 5, 6]
console.log(y.every(function(i){ return i >= 3; })); // true (全て3以上)
```

1つでも条件を満たす要素があるかどうかは`some`でこのように判定します。

```javascript
var x = [0, 1, 2]
console.log(x.some(function(i){ return i >= 3; })); // false (どれも3未満)
var y = [1, 2, 3]
console.log(y.some(function(i){ return i >= 3; })); // true (3があるので)
```

おわりに
---

以上高階関数のmapとfilterについて、入門的な説明でした。
普段のプログラミングでも使えそうな場面はたくさんあるのではないでしょうか。
ぜひfor文で書いている所を書き直しコードの見通しを良くしたり、変数やif文を減らしてみたりしてください。

参考
---

* [JavaScriptでforEach, filter, map, reduceとか](http://qiita.com/itagakishintaro/items/29e301f3125760b81302)
* [関数型プログラミングはまず考え方から理解しよう](http://qiita.com/stkdev/items/5c021d4e5d54d56b927c)
* [Array.prototype.map() - JavaScript _ MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map)