Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.
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^)/これ使えばもっとスマートに書けそうだ。なんかつかれた。

srea
SET, iOS, Android, PHP
https://minipro.co/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした