array_map_recursiveはPHPに標準実装されていた！

[RecursiveArrayIterator]: http://www.php.net/manual/ja/class.recursivearrayiterator.php
[ArrayIterator]: http://www.php.net/manual/ja/class.arrayiterator.php
[RecursiveIteratorIterator]: http://www.php.net/manual/ja/class.recursiveiteratoriterator.php
[IteratorIterator]: http://www.php.net/manual/ja/class.iteratoriterator.php
[iterator_to_array]: http://www.php.net/manual/ja/function.iterator-to-array.php
[array_map]: http://www.php.net/manual/ja/function.array-map.php

[unset]: http://www.php.net/manual/ja/function.unset.php
[array_walk]: http://www.php.net/manual/ja/function.array-walk.php

[array_walk_recursive]: http://www.php.net/manual/ja/function.array-walk-recursive.php

[filter_var]: http://www.php.net/manual/ja/function.filter-var.php

[is_array]: http://www.php.net/manual/ja/function.is-array.php

# 再帰の伴わない書き替え

## 問題

一次元配列`$a`の要素の値に全て1を加えたものを`$b`に代入せよ。

## 入出力例

```php:$a
[1, 3, 2, 8, 99]
```

```php:$b
[2, 4, 3, 9, 100]
```

## 解答例

### 一つずつ新しい配列に代入する

誰もが思いつく`foreach`構文を用いる方法です。

```php:foreach構文を用いる
$b = [];
foreach ($a as $key => $value) {
    $b[$key] = $value + 1;
}
```

この用途では[array_walk]関数を使うメリットはいまいち無さそう…

```php:array_walk関数を用いる
$b = [];
array_walk($a, function ($value, $key) use (&$b) {
    $b[$key] = $value + 1;
});
```

### 全体をコピーした後、1つずつ書き替える

PHPの`foreach`構文にはブロックスコープは存在しないため、ループを抜けた後に自分で[unset]を実行しないと最後の要素に対するリファレンスがずっと続いてしまいます。

```php:foreach構文を用いる
$b = $a;
foreach ($b as &$value) {
    ++$value;
}
unset($value);
```

最後に外側で[unset]を呼ぶのが不恰好だと感じる場合、[array_walk]関数で解決です。

```php:array_walk関数を用いる
$b = $a;
array_walk($b, function (&$value) {
    ++$value;
});
```

### コールバック関数を適用する

関数脳の人ならこれ一択でしょう。私も大好きです。

```php:array_map関数を用いる
$b = array_map(function ($value) {
    return $value + 1;
}, $a);
```

# 再帰の伴う書き替え

## 問題

任意の多次元配列`$a`の葉要素の値に全て1を加えたものを`$b`に代入せよ。

## 入出力例

```php:$a
[[1], [[3]], [[[2]]], [8], 99]
```

```php:$b
[[2], [[4]], [[[3]]], [9], 100]
```

## 解答例

[is_array]関数での判定を交えて手作業で再帰させる解答は省略します。ここでは**PHPの機能によって**再帰させる方法のみを紹介します。

### 全体をコピーした後、1つずつ書き替える

[array_walk]関数は[array_walk_recursive]関数の存在への布石としての意味合いが強いです。前者には *「それ`foreach`で良くね？」* という疑問が沸きそうな感じはありましたが、後者には明確な再帰という目的があります。

```php:array_walk_recursive関数を用いる
$b = $a;
array_walk_recursive($b, function (&$value) {
    ++$value;
});
```

### コールバック関数を適用する

*「`array_map_recursive`とかねーじゃん！？自分で作らないといけないんじゃないの？」* と思ったそこのあなた。実は…

**[filter_var]**関数の出番なんです。

<blockquote class="twitter-tweet" lang="ja"><p>物凄い種類の「何か」を識別する最強の呪文 &quot;filter_var&quot;</p>&mdash; NaOHaq(仮性ソーダ) (@NaOHaq) <a href="https://twitter.com/NaOHaq/status/565868022460854272">2015, 2月 12</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

まさかこんなところに出現するとは…

```php:filter_var関数を用いる
$b = filter_var($a, FILTER_CALLBACK, ['options' => function ($value) {
    return $value + 1;
}]);
```

これを紹介するためだけにこの記事を書きました（笑

#### **重要な追記**

上記の例では`+1`しているため問題ありませんでしたが，`$value`として渡されてくる値は全てオプション無しの`filter_var`を個別に通したような値になっています．すなわち，**`string`にキャストされるか`false`になっています**．

# 平坦化

## 問題

任意の多次元配列`$a`を平坦化して`$b`に代入せよ。キーは`0`からの連番整数を振りなおすものとする。

## 入出力例

```php:$a
[[1], [[3]], [[[2]]], [8], 99]
```

```php:$b
[1, 3, 2, 8, 99]
```

## 解答例

[is_array]関数での判定を交えて手作業で再帰させる解答は省略します。ここでは**PHPの機能によって**再帰させる方法のみを紹介します。

### 一つずつ新しい配列に代入する

[array_walk_recursive]関数を使う方法が一番理解しやすいと思います。もちろん[filter_var]でも実現することは出来ますが、今回はその返り値は使わずに逐次代入するだけなので、わざわざ[filter_var]を使う必要は無いでしょう。

```php:array_walk_recursive関数を用いる
$b = [];
array_walk_recursive($a, function ($value) use (&$b) {
    $b[] = $value;
});
```

但し、以下のような目的がある場合は[filter_var]のほうは配列もスカラー値も一貫して処理したい (配列でラップする必要がない)
- 

### 再帰イテレータを用いる

[RecursiveArrayIterator]クラスと[RecursiveIteratorIterator]クラスを用いて再帰イテレータを作成した後、それを[iterator_to_array]関数を用いて配列に変換します。

```php:RecursiveArrayIteratorクラスとRecursiveIteratorIteratorクラスを用いる
$b = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($a)), false);
```

ちなみにこれらに関しても非再帰版の[ArrayIterator]クラスと[IteratorIterator]クラスが再帰版への布石として存在します。