recursive('mb_convert_encoding', $ary, 'UTF-8', 'SJIS');
recursive('trim', $ary);
とか出来ればラクだよなー。
なので与え値可変長で、関数を再帰的に利用する関数を作ってみました。
ちなみに array_map_recursive も巷で見かけるけど array_map 自体が配列の処理が前提で、与え値にも配列を要求するので再帰処理として面倒(じゃない?)
他、使えそうなのって無かったよなぁ・・・。探す前に作ってしまうのは、仕事ってより骨休めの趣味なんだろなぁ。
「結果の違い」で結果の表記を間違っていましたので直しました。(同日修正)
ソース
※ ヘボい処理をシェイプアップにしました(2010/11/11)
※ php4 は __FUNCTION__ を 'recursive'(関数名)にした方が無難。
function recursive($fnc, $ary){
$arg = func_get_args();
foreach($ary as $key => $val){
$arg[1] = $val;
if(is_array($val)){
$ary[$key] = call_user_func_array(__FUNCTION__, $arg);
}else{
$ary[$key] = call_user_func_array($fnc, array_slice($arg, 1));
}
}
return $ary;
}
$arg = func_get_args();
foreach($ary as $key => $val){
$arg[1] = $val;
if(is_array($val)){
$ary[$key] = call_user_func_array(__FUNCTION__, $arg);
}else{
$ary[$key] = call_user_func_array($fnc, array_slice($arg, 1));
}
}
return $ary;
}
$arg = array_slice(func_get_args(), 2);
$new = array();
foreach($ary as $key => $val){
if(is_array($val)){
$tmp = array_merge(array($fnc), array($val), $arg);
$new[$key] = call_user_func_array('recursive', $tmp);
}else{
$tmp = array_merge(array($val), $arg);
$new[$key] = call_user_func_array($fnc, $tmp);
}
}
return $new;
}
■ 使い方
recursive('mb_convert_encoding', $ary, 'UTF-8', 'SJIS');
recursive('trim', $ary);
配列を与えると再帰的に処理された配列が返される。
与え値の数は最低2つ。
■ 自前の環境
PHP Version 5.2.3
System Windows NT
Server API Apache 2.0
call_user_func_array が PHP 4.0.4 から、それ以外は 4 からなので PHP 4.0.4 から動くかな。(未確認)
ちなみに func_get_args が関数内にあります。下記が面白いので参考下さい。
PHPのfunc_get_argsの謎
http://ido.nu/kuma/2007/07/03/php-wonders-func_get_args/
func_get_args(): Can't be used as ・・・ って怒られたら外に出して下さいw
ついでに array_walk_recursive も使いやすくしてみる
function walk(&$a, $b, $c = array()){
if(!is_array($a)){
$a = call_user_func_array(current(array_splice($c, 0, 1, $a)), $c);
}else{
$args = array_slice(func_get_args(), 1);
return array_walk_recursive($a, 'walk', $args);
}
}
if(!is_array($a)){
$a = call_user_func_array(current(array_splice($c, 0, 1, $a)), $c);
}else{
$args = array_slice(func_get_args(), 1);
return array_walk_recursive($a, 'walk', $args);
}
}
※ array_walk_recursive は PHP 5 からです。
実質的には recursive() と同じ結果が得られます。違いは・・・。
・ 与え値は array_walk_recursive の順序に準ずる
・ array_walk_recursive 同様に参照渡しになる
・ 処理された配列は array_walk_recursive 同様に参照を含む
・ 戻り値は array_walk_recursive に準ずる
■ 使い方
walk($ary, 'mb_convert_encoding', 'UTF-8', 'SJIS');
walk($ary, 'trim');
配列を与えると再帰的に処理された配列が返される。
当然、結果は $ary に直接入る。
■ 結果の違い
・ テスト関数
function f($v1, $v2, $v3){return ($v1 * $v2 + $v3);}
・ テスト配列
$ary = array(array(0,1,2), array(array(10, 11, 12), array(20, 21, 22)));
recursive()の場合
var_dump(recursive('f', $ary, 3, 2));
array
0 =>
array
0 => int 2
1 => int 5
2 => int 8
1 =>
array
0 =>
array
0 => int 32
1 => int 35
2 => int 38
1 =>
array
0 => int 62
1 => int 65
2 => int 68
0 =>
array
0 => int 2
1 => int 5
2 => int 8
1 =>
array
0 =>
array
0 => int 32
1 => int 35
2 => int 38
1 =>
array
0 => int 62
1 => int 65
2 => int 68
walk()の場合
walk($ary, 'f', 3, 2);
var_dump($ary);
array
0 => &
array
0 => int 2
1 => int 5
2 => int 8
1 => &
array
0 => &
array
0 => int 32
1 => int 35
2 => int 38
1 => &
array
0 => int 62
1 => int 65
2 => int 68
0 => &
array
0 => int 2
1 => int 5
2 => int 8
1 => &
array
0 => &
array
0 => int 32
1 => int 35
2 => int 38
1 => &
array
0 => int 62
1 => int 65
2 => int 68
さらについでに array_map_recursive の例2種
for を使わない方法
function array_map_recursive($f, $v)
{
return
(
is_array($v) ?
(
!empty($v) ?
array_combine(
array_keys($v),
array_map(
'array_map_recursive',
array_fill(0, count($v), $f),
$v
)
)
: $v
)
: $f($v)
);
}
{
return
(
is_array($v) ?
(
!empty($v) ?
array_combine(
array_keys($v),
array_map(
'array_map_recursive',
array_fill(0, count($v), $f),
$v
)
)
: $v
)
: $f($v)
);
}
for を使った方法(こちのが速い)
function array_map_recursive($cb, $dat){
if(is_array($dat)){
$new = array();
foreach($dat as $k => $v){
if(is_array($v)) $new[$k] = array_map_recursive($cb, $v);
else $new[$k] = call_user_func($cb, $v);
}
return $new;
}else return call_user_func($cb, $dat);
}
if(is_array($dat)){
$new = array();
foreach($dat as $k => $v){
if(is_array($v)) $new[$k] = array_map_recursive($cb, $v);
else $new[$k] = call_user_func($cb, $v);
}
return $new;
}else return call_user_func($cb, $dat);
}
とは言え与え値が渡せないので、与え値不要の関数にしか使えない。
この記事へのコメント