人気ブログランキング | 話題のタグを見る

[PHP] array_splice で配列の要素を削除する

わかってしまえば、なぁんだってことなのだけど、すごく悩んだので。

php の配列は(見た目は) 2 種類。

hash ぽいものと、array ぽいもの。
// array ぽい
$input_a = array("red", "green", "blue", "yellow");
// hash ぽい
$input_h = array("r"=>"red", "g"=>"green", "b"=>"blue", "y"=>"yellow");


配列から要素を削除する場合、
unset を使いなさいと書かれている。
「php 配列 要素 削除」で検索しても、大体 unset しか出てこない。
マニュアルにはこんな風に。
// 配列の要素の一つを破棄する
unset ($bar['quux']);


これは hash のときに有効なので、以下は有効。
// $input_h['r'] から "red" を取り出せなくなる
unset ($input_h['r']);


じゃ、これは array の方にも有効なんだろうか。
array に見えるものも、
実は中身はインデックスを添え字とした hash になっている。
上に、配列は見た目 2 種類と書いたのはこういうわけで、
実は 1 種類しかない。
つまり以下の 2 つは内部的に等価。
// こんな風に宣言しても
$input_a = array("red", "green", "blue", "yellow");
// 内部では、こんな風に宣言されたのと同じ
$input_a = array(0=>"red", 1=>"green", 2=>"blue", 3=>"yellow");


ってことは、当然 unset で消せる。
// "red" が消える
unset ($input_a[0]);

確かに消えるよ。

しかし、通常 array ぽい宣言をした方は、
順序が保証されていると(頭の中で)思って使うので、
0 から順に値を取り出してみると、
次のようなエラーが出る。
// 値を取り出してみる
for($i=0 ; $i<count($input_a) ; $i++) {
 echo $input_a[$i];
}

PHP Notice: Undefined offset: 0 in test.php on line **


なんでかっつーと、$input_a[0] を消したので、
0 というキーがなくなっちゃって、アクセスできなくなってるのね。
そうなの?と思いつつ、キーを表示してみると、こんな感じ。
// hash キーをカンマ区切りで表示してみる
implode (',', array_keys($input_a));

-> 1,2,3

あらホントに 0 が消えてるわよ。

じゃ、array の場合、キーも値も一緒に消すにはどうしたらいいか。
つまり、値もキーも消して、キーとなっている添え字を詰めて欲しい。
すごく探し回って array_splice を使ってみたら、うまくいった。
// 先頭の要素を 1 つ消す
array_splice($input_a, 0, 1);
implode (',', array_keys($input_a));

-> 0,1,2

おお消えた!
ま、先頭1コなら、通常popを使っちゃうけどね。

なんでこんなことをしたかったのかというと、
3つの要素を持つ配列があって、
その要素が更に配列。
図にすると、こんな感じ。
(ここからは等幅フォントで見てね)

元の配列。
┌─────────┬─────────┬─────────┐
│┌─┬─┬─┬─┐│┌─┬─┬─┬─┐│┌─┬─┬─┬─┐│
││A │B │C │D │││E │F │G │H │││I │J │K │L ││
│└─┴─┴─┴─┘│└─┴─┴─┴─┘│└─┴─┴─┴─┘│
└─────────┴─────────┴─────────┘

各要素の第1要素である A と E と I を比較して、
この配列をソートしたかった。

例えば、上の元の配列から B を unset で削除するとこうなる。
┌─────────┬─────────┬─────────┐
│┌─┬─┬─┬─┐│┌─┬─┬─┬─┐│┌─┬─┬─┬─┐│
││A │  │C │D │││E │F │G │H │││I │J │K │L ││
│└─┴─┴─┴─┘│└─┴─┴─┴─┘│└─┴─┴─┴─┘│
└─────────┴─────────┴─────────┘

第1要素である A E I はそのままだから、
A E I でソートしてもエラーは出ない。

ところが、元の配列から E を unset で削除するとこうなる。
┌─────────┬─────────┬─────────┐
│┌─┬─┬─┬─┐│┌─┬─┬─┬─┐│┌─┬─┬─┬─┐│
││A │B │C │D │││  │F │G │H │││I │J │K │L ││
│└─┴─┴─┴─┘│└─┴─┴─┴─┘│└─┴─┴─┴─┘│
└─────────┴─────────┴─────────┘

ソートするためのキーである第1要素がないので、
A I のところは大丈夫だけど、E があったはずのところところでエラーになる。

なので、E を削除して、更に要素も詰めて、第1要素でソートするためには、
配列は、こうなっていて欲しい。
┌─────────┬───────┬─────────┐
│┌─┬─┬─┬─┐│┌─┬─┬─┐│┌─┬─┬─┬─┐│
││A │B │C │D │││F │G │H │││I │J │K │L ││
│└─┴─┴─┴─┘│└─┴─┴─┘│└─┴─┴─┴─┘│
└─────────┴───────┴─────────┘

このために、 array_splice を使うのね、という話でした。


第1要素がなかったら、次の要素を見る、という風に書いてもよかったんだけど、
それは違うよなぁ、なんか方法あるでしょ常考、という気がしていたのよね。
文字で説明するとややこしいなぁ。

まとめるとこんな感じ。
  • array も hash も中身は hash
  • hash から要素を削除するのは unset
  • array から要素を削除するのは array_splice


こんな簡単なことに数時間悩んでしまった。
なわけで「php 配列 要素 削除」で検索したときに、
array_splice も引っかかったらいいなーと思いつつ、
この記事を書いてみたYO!

LL に限って言えば、
array や hash は、言語によって実装が違うので、
内部がどうなっているか考えながら書かないとなぁ。
つか、この辺がわかると、
その言語の結構な部分が理解できるんじゃないかと思っている。
javascript は object 自体が全部 hash 、とかそういうところ。
かなり言語の特色が出る部分じゃないかと。
by xiaoxia | 2008-09-08 12:54 | プログラム言語
<< カラオケのキーについて 梶浦ライブ行ってきたよ >>