PHPのarrayはすごいです！いろいろできます！奥深い！

PHPの`array`はすごいです。いろいろできます。以前[PHPのlist()はタプル展開のための機能 - Qiita](http://qiita.com/tadsan/items/0beaf61747397c1e3db8)といふ記事を書いて「配列はタプルだったんだよ！！！！」と力説したのですが、それ以外のデータ構造としての特徴について挙げていきます。

~~タイトルはてきとー。~~ (原題: <q>All your data structure are belong to ARRAY.</q> は [All your base are belong to us - Wikipedia](https://ja.wikipedia.org/wiki/All_your_base_are_belong_to_us)が元ねた。)

## PHPのarray

*この節の内容は再掲です。*

PHPの配列は、その名前に反して、実に多様な機能を併せ持った[データ型](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B)です。

> PHP の配列は、実際には順番付けられたマップです。マップは型の一種で、 値をキーに関連付けます。 この型は、さまざまな使い道にあわせて最適化されます。 <mark>_配列_</mark>としてだけでなく、<mark>_リスト_</mark> (<mark>_ベクター_</mark>)、 <mark>_ハッシュテーブル_</mark> (<mark>_マップ_</mark>の実装の一つ)、<mark>_辞書_</mark>、<mark>_コレクション_</mark>、<mark>_スタック_</mark>、 <mark>_キュー_</mark>等として使用することが可能です。 PHP の配列には他の PHP 配列を値として保持することができるため、 非常に簡単に<mark>_ツリー構造_</mark>を表現することが可能です。
>
> *php.net, [PHP: 配列 - Manual](http://php.net/manual/ja/language.types.array.php), 2016年8月12日閲覧. 引用は@tadsanによる.*

以上のように、PHPにおける配列(`array`)は、数多くのデータ構造の機能を兼ねて持ちます。[大クラス主義を標榜する](http://www.atmarkit.co.jp/news/200712/25/ruby.html)[RubyのArray](http://docs.ruby-lang.org/ja/2.1.0/class/Array.html)よりも、さらに大ざっぱです。

本記事では、`array`の特性を活かして、ここに言及された種々のデータ構造として活用するための方法を紹介します。あと、ややこしいので本記事ではこれ以降、「PHPの配列型(`array`)」のことを全て**array**と表記します。

## 配列

そもそもの話になりますが、PHPの[array](http://php.net/manual/ja/language.types.array.php)は、いはゆるC言語の配列とは**まったく別物です**。

ちょっとぐぐればWeb上にはC言語の資料はたくさんみつかりますが、ここでは京都産業大学の山田修司先生による[配列（array）](http://www.cc.kyoto-su.ac.jp/~yamada/programming/array.html)の資料を参考にします。

C言語の配列の初期化は以下のように、**型宣言**と**要素数**を記述する必要があります。C言語の配列のように要素数が固定化された配列を特に「固定長配列」と呼びます。

```c
// 要素数10の配列
int a[10];
// 要素数10の配列 (変数宣言と同時に代入するときは要素数を省略できる)
int b[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
```

ご存じのようにPHPのarray(配列)は要素数の設定は必要ありませんし、型を固定する必要もありません。

また、C言語の配列でも「配列の配列」(二次元配列または多次元配列)を扱ふことができますが、その場合すべての配列のサイズが揃ってる必要があります。当然、PHPのarrayにそのような制約はありません。


```c
#include <stdio.h>

int main(void) {
    int b[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};

    for (int i = 0; i < (sizeof b / sizeof b[0]); i++) {
        printf("%d\n", b[i]);
    }
    return 0;
}
```

このCのコードをPHPで書くと以下のようになります。

```php
<?php

$b = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];

for ($i = 0; $i < count($i); $i++) {
    printf("%d\n", $b[$i]);
}
exit(0);
```

```php
// for より foreach を使った方がかんたん
foreach ($b as $i) {
    echo $n, "\n";
}
```

C言語から派生した要素が強いC++とかJavaでは<ruby>**生配列**<rt>なまはいれつ</ruby>と呼ばれ、必要に迫られなければ触れるべきではないものだと見做されてる感がありますね。私はC++もJavaも書かないので実際どうなのか知りませんが。

あとPHPの標準ライブラリには固定長配列の実装として[`SplFixedArray`](http://php.net/manual/ja/class.splfixedarray.php)クラスがありますが、筆者は実用したことはないです。~~arrayでいいじゃｎ~~

ちなみにC言語版のコードについてまめちしきを申し上げますと、C言語の`sizeof`は函数ではなく演算子なので、`sizeof(b)`ではなく`sizeof b`と書いて問題ありません。一方でPHPにも[`sizeof()`](http://php.net/manual/ja/function.sizeof.php)はあるのですが、これは[`count()`](http://php.net/manual/ja/function.count.php)のエイリアスで、ただの函数です。(つまりPHPで`sizeof $b`とは書けません)

## リスト

プログラミングの分野でも「[リスト](https://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%B9%E3%83%88_(%E6%8A%BD%E8%B1%A1%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B))」の持つ意味は多義的で、まあデータを順番に並べたもの程度の意味です。もちろんPHPのarrayもデータを順番にいっぱい並べられるので、リストです。

「リスト」の名前でよく知られたデータ構造としては[連結リスト](https://ja.wikipedia.org/wiki/%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88)がありますが、**PHPのarrayとは特に関係ありません**。 *(とても簡単に実装できるので、PHPの練習がてら実装してみるのはおもしろいです)*

Wikipedia日本語版には以下のようにあります。

> リストの実装方法には主に2つある。[連結リスト](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E3%83%AA%E3%82%B9%E3%83%88)（片方向または双方向）と[動的配列](https://ja.wikipedia.org/wiki/%E5%8B%95%E7%9A%84%E9%85%8D%E5%88%97)である。

*([リスト (抽象データ型) - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%B9%E3%83%88_(%E6%8A%BD%E8%B1%A1%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B)) [2016-01-23T15:19:55‎](https://ja.wikipedia.org/w/index.php?title=%E3%83%AA%E3%82%B9%E3%83%88_(%E6%8A%BD%E8%B1%A1%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B)&oldid=58337049)の版より引用)*

され、我らがPHPのarrayの実装はといふと、PHP 5時代は「[ハッシュテーブル](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB)」、PHP 7では「動的配列(可変長配列)とハッシュテーブル」(処理系が自動的に選択する)になります。(詳しくは@hnwさんの[PHP7の内部実装から学ぶ性能改善テクニック](http://www.slideshare.net/hnw/php7-52408724)が参考になります)

## ベクター

PHPマニュアルにはしれっと<q>リスト(ベクター)</q>とかセットでしれっと書いてあるんですが、リストと[ベクトル](https://ja.wikipedia.org/wiki/%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB)では言葉の範囲がだいぶ異なるような… さておき、コンピュータの世界ではリストに負けず劣らずいろんな意味がありますね。

それはさておいて、PHPマニュアルの著者はC++の[`std::vector`](http://cpprefjp.github.io/reference/vector.html)について言及したかったのではないでせうか。これは[Standard Template Library](https://ja.wikipedia.org/wiki/Standard_Template_Library)と呼ばれるC++の標準ライブラリに含まれるデータ構造で、可変長配列のことです。

PHPではメモリ確保などは自動でやってくれるので、ユーザーは深く考へず適当に書いてればPHP処理系がいい感じにしてくれます。

私は中学校の算数と理科で挫折した人間なのでおそらくベクトルについては読者のみなさまの方が詳しいと思ふのですが、世の中では「ベクトル」の対義語とは「スカラー」だとのことです。

PHPでスカラー値と呼ばれるのは`bool`/`int`/`float`/`string`の四つの型の値です。[`is_scalar()`](http://php.net/manual/ja/function.is-scalar.php)函数でチェックすることができます。`resource`と`null`はスカラーではない、特別な型です。では`array`と`object`は「ベクター」なのかといふと違って、「複合型(compound types)」と申します。

## ハッシュテーブル(マップ)

ここでの「マップ」とは[連想配列](https://ja.wikipedia.org/wiki/%E9%80%A3%E6%83%B3%E9%85%8D%E5%88%97)*(associative array)*のことで、[`array_map`](http://php.net/manual/ja/function.array-map.php)のようなmap函数とは関係ありません。通常の配列が数値のインデックスしか利用できないのに対して、<dfn>**連想配列**</dfn>は数値以外のデータをインデックスにできるようにしたものです。

[ハッシュテーブル](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB)は連想配列を実現する効率的なデータ構造として知られます。この名前はインデックスから生成した[ハッシュ値](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0)を利用することからこの名前で呼ばれます。

PerlやRubyでは連想配列のことを**Hash**と呼びますが、ハッシュ値やハッシュ函数と混同されかねず、あまり良い名付けではないと思ひます。また、PHPマニュアルの[PHP: Hash 関数 - Manual](http://php.net/manual/ja/ref.hash.php)はもちろん連想配列についての函数ではなく、ハッシュ函数です。

PHPのarrayは連想配列がベースであるために、「連番の数字のみインデックスにした配列」と「文字列インデックスを使った連想配列」の区別を付けにくい問題があります。あるarrayを連想配列ではない配列に変換するには[`array_values()`](http://php.net/manual/ja/function.array-values.php)を利用することができます。

また、マップの実現方法は別にハッシュテーブルだけではありません。Lispでは単方向リストを応用した「連想リスト([Association list](https://en.wikipedia.org/wiki/Association_list))」がしばしば用ゐられます。これはデータ構造がとにかく簡単で、[PHPでも非常に簡単に実装できます](https://github.com/BaguettePHP/Functools/blob/master/src/Functools/DataStructure/Cons.php#L113-L119)。

## 辞書(ディクショナリ)

連想配列と同じような意味なので個別に説明するようなことはあまりありません。Pythonの連想配列は[`dict`](http://docs.python.jp/3.5/library/stdtypes.html#mapping-types-dict)(辞書)と呼ばれます。

あと、竹内郁雄先生の「初めての人のためのLISP[増補改訂版]」って本では環境(変数のリストのようなもの)を[「辞書」と表現](https://books.google.co.jp/books?id=LnQaBwAAQBAJ&lpg=PT226&ots=5PhtapihCf&dq=lisp%20%E7%92%B0%E5%A2%83%20%E8%BE%9E%E6%9B%B8&hl=ja&pg=PT212#v=onepage&q=lisp%20%E7%92%B0%E5%A2%83%20%E8%BE%9E%E6%9B%B8&f=false)されてましたね。

PHPのarrayの問題点としては、intとstringの値しかインデックスに利用できない問題があります。もしどうしてもオブジェクトや配列をインデックスにした辞書を実現したくなった場合、上で紹介した連想リストを自作してみるのもひとつ有効な手段かもしれませんね。

## コレクション

これも「データを集めたもの」程度の意味です。ただ、リストと違って「順番に並べた」みたいなニュアンスは含まれません。[コレクション概要 - アルゴリズムとデータ構造 | ++C++; // 未確認飛行 C](http://ufcpp.net/study/algorithm/collection.html)などを眺めると、はあ世のなかにはいろんなコレクションがあるんだなあ、といふ気持ちになりますね。

その中でも目を引くのは[セット](https://ja.wikipedia.org/wiki/%E3%82%BB%E3%83%83%E3%83%88_(%E6%8A%BD%E8%B1%A1%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B))ですかね。これは、[集合](https://ja.wikipedia.org/wiki/%E9%9B%86%E5%90%88)を表現するデータ構造の総称です。

### 集合

集合とは何かと考へはじめると僕のような数学音痴は秒速で頭がばくはつしかねないのですが、ぱそこんの世界では「重複のないデータの集まり」のような機能が一般的です。

arrayを使って擬似的に集合を表現する方法としては、「arrayのインデックスを利用する方法」と「[`array_unique()`](http://php.net/manual/ja/function.array-unique.php)で重複を排除する方法」などがあります。ただし、これらの手法は文字列として表現可能な値にしか適用できないことも気をつけてください。

また、PHPの標準函数には配列を使って集合っぽい操作をするための機能がいくつもあります。

- [差集合](https://ja.wikipedia.org/wiki/%E5%B7%AE%E9%9B%86%E5%90%88)
    - [`array_diff()`](http://php.net/manual/ja/function.array-diff.php) / [`array_udiff()`](http://php.net/manual/ja/function.array-udiff.php)
    - [`array_diff_assoc()`](http://php.net/manual/ja/function.array-diff-assoc.php) / [`array_diff_uassoc()`](http://php.net/manual/ja/function.array-diff-uassoc.php)
    - [`array_diff_key()`](http://php.net/manual/ja/function.array-diff-key.php) / [`array_diff_ukey()`](http://php.net/manual/ja/function.array-diff-ukey.php)
    - [`array_udiff_assoc()`](http://php.net/manual/ja/function.array-udiff-assoc.php) / [`array_udiff_uassoc()`](http://php.net/manual/ja/function.array-udiff-uassoc.php)
- [共通集合](https://ja.wikipedia.org/wiki/%E5%85%B1%E9%80%9A%E9%83%A8%E5%88%86_(%E6%95%B0%E5%AD%A6)) (積集合)
    - [`array_intersect()`](http://php.net/manual/ja/function.array-intersect.php) / [`array_uintersect()`](http://php.net/manual/ja/function.array-uintersect.php)
    - [`array_intersect_assoc()`](http://php.net/manual/ja/function.array-intersect-assoc.php) / [`array_intersect_uassoc()`](http://php.net/manual/ja/function.array-intersect-uassoc.php)
    - [`array_intersect_key()`](http://php.net/manual/ja/function.array-intersect-key.php) / [`array_intersect_ukey()`](http://php.net/manual/ja/function.array-intersect-ukey.php)
    - [`array_uintersect_assoc()`](http://php.net/manual/ja/function.array-uintersect-assoc.php) / [`array_uintersect_uassoc()`](http://php.net/manual/ja/function.array-uintersect-uassoc.php)

果たしてこんなに標準函数は必要なのかと疑問をおぼえるほど大量にありますね… あと[和集合](https://ja.wikipedia.org/wiki/%E5%92%8C%E9%9B%86%E5%90%88)(union)についての標準函数がないのは`array_unique(array_merge($a, $b))`とかやっていい感じにしろってことなんですかね。

## スタック

[スタック](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF)もデータを順番に並べるデータ構造ですが、特徴はデータを[後入れ先出し](https://ja.wikipedia.org/wiki/%E5%BE%8C%E5%85%A5%E5%85%88%E5%87%BA%E6%B3%95)(**LIFO**: Last In First Out)することです。

スタックに対する基本的な操作は**push**と**pop**です。これに対応する標準函数、配列の末尾にデータを追加する[`array_push()`](http://php.net/manual/ja/function.array-push.php)と配列の末尾からデータを取り出す[`array_pop()`](http://php.net/manual/ja/function.array-pop.php)です。ただし、`array_push($array, $d)`は`$array[] = $d`と書くことができるので、ふつうあまり利用されません。

また、SPL(標準PHPライブラリ)にはシンプルなスタックの実装として[`SplStack`](http://php.net/manual/ja/class.splstack.php)クラスがあります。

## キュー

[キュー](https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A5%E3%83%BC_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF))もスタックと同じように、データを順番に並べるデータ構造です。キューは日本語で「待ち行列」とも呼ばれ、お行儀よく順番に処理するのが特徴です。ただしPHPでは先頭と末尾のどちらにデータを追加することも、取り出すことも支障がないため、[両端キュー](https://ja.wikipedia.org/wiki/%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC)に相当します。

シンプルなキューにデータを詰める操作を**enqueue**、取り出す操作を**dequeue**といって、これはそれぞれ[`array_shift()`](http://php.net/manual/ja/function.array-shift.php)と[`array_push()`](http://php.net/manual/ja/function.array-push.php)が相当します。また、[`array_unshift()`](http://php.net/manual/ja/function.array-unshift.php)は配列の先頭にデータをつっこみます。

また、SPL(標準PHPライブラリ)にはシンプルなキューの実装として[`SplQueue`](http://php.net/manual/ja/class.splqueue.php)クラスと、優先度付きキューの実装として[`SplPriorityQueue `](http://php.net/manual/ja/class.splpriorityqueue.php)クラスがあります

## ツリー(木構造)

[木 (数学)](https://ja.wikipedia.org/wiki/%E6%9C%A8_(%E6%95%B0%E5%AD%A6))と[木構造 (データ構造)](https://ja.wikipedia.org/wiki/%E6%9C%A8%E6%A7%8B%E9%80%A0_(%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0))を読んでください…  身近にあるいろんなもののデータの構造は木構造です。たとへばディレクトリの階層構造とか、HTMLのタグの階層構造だとかが言及しやすい例です。

あとはプログラミング言語で書かれたソースコードは基本的に処理の過程でなんらかの形で木構造に落とし込まれることがあります。PHP 7では[コンパイル時にASTを構築するようになった](http://qiita.com/hnw/items/4dfdcc6a3eace7fe1936)ことが話題になりましたね[^1]。

## タプル

[PHPのlist()はタプル展開のための機能 - Qiita](http://qiita.com/tadsan/items/0beaf61747397c1e3db8)に書きました。

## まとめ

みなさまもarrayのポテンシャルを発揮して楽しいPHPライフを！

## 脚注

[^1]: ここに長いポエムがあったけど、削った