32
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[php]多次元配列でもin_arrayを使えるようにする関数をクロージャを使って実装

Posted at
in_arrayのfalse例
<?php
$array = array( 0 => array('id' => 1000),
                1 => array('id' => 3000));
var_dump(in_array(3000, $array)); // bool(false)

配列の中にある値が入ってるか確認したい時に、in_arrayを使いたくても1次元配列までしか対応してないから上手く処理が出来ない。

in_arrayのtrue例
<?php
$array = array( 0 => array('id' => 1000),
                1 => array('id' => 3000));
// 配列固有の処理
$list = array();
foreach ($array as $a) {
    $list[] = $a['id'];
}
var_dump(in_array(3000, $list)); // bool(true)

上記のようにすれば実現出来るけど、こういう物は様々な場所で利用する事があるかもしれないから、出来れば共通に使えるように抽象化したい。

array_valuesは多次元配列に対応していないから、今回はクロージャを使って実装してみた。
useを使って自分自身を参照させ再帰処理出来るようにしてる。だからPHP5.3以降のみ対応

<?php
// 多次元配列のテストデータ
$test_array = array(array(
    'aaaa'=> 'a',
    'bbbb'=> array('b'),
    'cccc'=> array(array('cccc'=>'c')),
    'dddd'=> array(array(array('dddd'=>'d','eeee'=>'e'))),
    'ffff'=>'f',
    'gggg'=>array(array(array(array(array(array(array('g')))))))
    ),array(array('hhhh'=>array(array('iiii'=>array('h','i'))))));
array_push($test_array,'j','k');
$test_array['llll'] = 'l';

// array_valuesの再帰
function array_values_recursive ($a = array()) {
    $r = function ($a) use (&$r) {
        static $v = array();
        foreach ($a as $ary) {
            is_array($ary) ? $r($ary) : $v[] = $ary;
        }
        return $v;
    };
    return $r($a);
}
// テストデータからvalues値だけ取ってくる。
var_dump(array_values_recursive($test_array));

メモリ使用効率とか考えるともっともっと最適化できる気がする。

再帰処理前
array(5) {
  [0]=>
  array(6) {
    ["aaaa"]=>
    string(1) "a"
    ["bbbb"]=>
    array(1) {
      [0]=>
      string(1) "b"
    }
    ["cccc"]=>
    array(1) {
      [0]=>
      array(1) {
        ["cccc"]=>
        string(1) "c"
      }
    }
    ["dddd"]=>
    array(1) {
      [0]=>
      array(1) {
        [0]=>
        array(2) {
          ["dddd"]=>
          string(1) "d"
          ["eeee"]=>
          string(1) "e"
        }
      }
    }
    ["ffff"]=>
    string(1) "f"
    ["gggg"]=>
    array(1) {
      [0]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          array(1) {
            [0]=>
            array(1) {
              [0]=>
              array(1) {
                [0]=>
                array(1) {
                  [0]=>
                  string(1) "g"
                }
              }
            }
          }
        }
      }
    }
  }
  [1]=>
  array(1) {
    [0]=>
    array(1) {
      ["hhhh"]=>
      array(1) {
        [0]=>
        array(1) {
          ["iiii"]=>
          array(2) {
            [0]=>
            string(1) "h"
            [1]=>
            string(1) "i"
          }
        }
      }
    }
  }
  [2]=>
  string(1) "j"
  [3]=>
  string(1) "k"
  ["llll"]=>
  string(1) "l"
}
こんな複雑な配列でも
再帰処理後
array(12) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(1) "d"
  [4]=>
  string(1) "e"
  [5]=>
  string(1) "f"
  [6]=>
  string(1) "g"
  [7]=>
  string(1) "h"
  [8]=>
  string(1) "i"
  [9]=>
  string(1) "j"
  [10]=>
  string(1) "k"
  [11]=>
  string(1) "l"
}

綺麗になりました(´ω`)

最初のin_arrayの例に適用するとこうなる。

in_arrayの例
<?php
function array_values_recursive ($a = array()) {
    $r = function ($a) use (&$r) {
        static $v = array();
        foreach ($a as $ary) {
            is_array($ary) ? $r($ary) : $v[] = $ary;
        }
        return $v;
    };
    return $r($a);
}
$array = array( 0 => array('id' => 1000),
                1 => array('id' => 3000));
$array = array_values_recursive($array);
var_dump(in_array(3000, $array)); // bool(true)

今更ながら、in_arrayする分にはin_array側を再帰チェック出来るように拡張したほうが良かった気がしてきた・・・

in_array_recursive版
<?php
function in_array_recursive ($val, $a = array()) {
    $r = function ($v,$a) use (&$r) {
        static $bool = false;
        if ($bool === true) return true;        
        foreach ($a as $ary) {
            is_array($ary) && $r($v, $ary);
            if ($v == $ary) {
                $bool = true;
            }
        }
        return $bool;
    };
    return $r($val, $a);
}
$array = array( 0 => array('id' => 1000),
                1 => array('id' => 3000));
var_dump(in_array_recursive(3000, $array)); // bool(true)

valueが数値とかで小さければ、keyに置き換えて isset($list[$key])でチェック出来て尚良いかもしれない

っというかSPLのイテレータの中に
RecursiveArrayIterator
RecursiveIteratorIterator
あるじゃん\(^o^)/これ使えばもっとスマートに書けそうだ。なんかつかれた。

32
32
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?