Php 在嵌套数组中查找内部数组

Php 在嵌套数组中查找内部数组,php,arrays,nested,Php,Arrays,Nested,我在PHP中有一个嵌套数组: array ( '0' => "+5x", '1' => array ( '0' => "+", '1' => "(", '2' => "+3", '3' => array ( '0' => "+", '1' => "(", '2' => array ( // I want

我在PHP中有一个嵌套数组:

array (
'0' => "+5x",
'1' => array (
       '0' => "+",
       '1' => "(",
       '2' => "+3",
       '3' => array (
              '0' => "+",
              '1' => "(",
              '2' => array ( // I want to find this one.
                  '0' => "+",
                  '1' => "(",
                  '2' => "+5",
                  '3' => "-3",
                  '4' => ")"
                  ),
              '3' => "-3",
              '4' => ")"
              ),
       '4' => ")"
       )
);       
我需要在这里处理最里面的数组,一个带有注释的数组:“我想找到这一个。”是否有一个函数用于此

我曾考虑过这样做(作为一个想法,而不是正确的PHP编写):

因此,它的作用是使
$name
成为数组中的当前键。如果该值是一个数组,则它与foreach一起进入该数组,并添加“.”和数组的id。因此,在示例阵列中,我们将以:

array (
    '0' => "1.3.2",
)
然后我可以处理这些值以访问Inner数组

问题是,我试图查找的内部数组是动态的,由用户输入组成。(它在找到+或-,的位置拆分输入字符串,如果包含方括号,则将其放入单独的嵌套数组中。因此,如果用户键入大量方括号,则将有大量嵌套数组。) 因此,我需要使这个模式向下运行20次,但不管发生什么情况,它仍然只能捕获20个嵌套数组


还有一个功能吗?或者有没有一种方法可以让它不用我的长代码就可以做到这一点?可能会制作一个循环,生成foreach模式的必要编号,并通过
eval()

运行它。请尝试以下代码并告诉我结果

只需将数组传递给
find\u
函数即可

function find_deepest( $array )
{
    $index       = '';        // this variable stores the current position (1.2, 1.3.2, etc.)
    $include     = true;      // this variable indicates if the current position should be added in the result or not
    $result      = array();   // this is the result of the function, containing the deepest indexes
    $array_stack = array();   // this is a STACK (or LIFO) to temporarily store the sub-arrays - see http://en.wikipedia.org/wiki/LIFO_%28computing%29
    reset( $array );          // here we make the array internal POINTER move to the first position

    // each loop interaction moves the $array internal pointer one step forward - see http://php.net/each
    // if $current value is null, we reached the end of $array; in this case, we will also continue the loop, if the stack contains more than one array
    while ( ( $current = each( $array ) ) || ( count( $array_stack ) > 1 ) )
    {
        // we are looping $array elements... if we find an array (a sub-array), then we will "enter it...
        if ( is_array( $current['value'] ) )
        {
            // update the index string
            $index .= ( empty ( $index ) ? '' : '.' ) . $current['key'];
            // we are entering a sub-array; by default, we will include it
            $include = true;
            // we will store our current $array in the stack, so we can move BACK to it later
            array_push( $array_stack, $array );
            // ATTENTION! Here we CHANGE the $array we are looping; here we "enter" the sub-array!
            // with the command below, we start to LOOP the sub-array (whichever level it is)
            $array = $current['value'];
        }
        // this condition means we reached the END of a sub-array (because in this case "each()" function has returned NULL)
        // we will "move out" of it; we will return to the previous level
        elseif ( empty( $current ) )
        {
            // if we reached this point and $include is still true, it means that the current array has NO sub-arrays inside it (otherwise, $include would be false, due to the following lines)
            if ( $include )
                $result[] = $index;
            // ATTENTION! With the command below, we RESTORE $array to its precedent level... we entered a sub-array before, now we are goin OUT the sub-array and returning to the previous level, where the interrupted loop will continue
            $array = array_pop( $array_stack );
            // doing the same thing with the $index string (returning one level UP)
            $index = substr( $index, 0, strrpos( $index, '.' ) );
            // if we are RETURNING one level up, so we do NOT want the precedent array to be included in the results... do we?
            $include = false;
        }
        // try removing the comment from the following two lines! you will see the array contents, because we always enter this "else" if we are not entering a sub-array or moving out of it
        // else
        //   echo $index . ' => ' . $current['value'] . '<br>';
    }
    return $result;
}

$result = find_deepest( $my_array );
print_r( $result );
函数查找($array)
{
$index='';//此变量存储当前位置(1.2、1.3.2等)
$include=true;//此变量指示是否应在结果中添加当前位置
$result=array();//这是函数的结果,包含最深的索引
$array_stack=array();//这是一个临时存储子数组的堆栈(或LIFO)-请参阅http://en.wikipedia.org/wiki/LIFO_%28computing%29
reset($array);//这里我们将数组内部指针移动到第一个位置
//每个循环交互都会将$array内部指针向前移动一步-请参阅http://php.net/each
//如果$current值为null,则到达$array的末尾;在本例中,如果堆栈包含多个数组,则还将继续循环
而(($current=each($array))| |(count($array_stack)>1))
{
//我们正在循环$array元素…如果我们找到一个数组(子数组),那么我们将“输入它…”。。。
if(是_数组($current['value']))
{
//更新索引字符串
$index.=(空($index)“:”).$current['key'];
//我们正在输入一个子数组;默认情况下,我们将包含它
$include=true;
//我们将把当前的$数组存储在堆栈中,以便以后可以返回到它
array\u push($array\u stack,$array);
//注意!我们在这里更改正在循环的$数组;在这里“输入”子数组!
//使用下面的命令,我们开始循环子数组(无论它是哪个级别)
$array=$current['value'];
}
//这个条件意味着我们到达了子数组的末尾(因为在本例中“each()”函数返回NULL)
//我们将“走出”它;我们将回到以前的水平
elseif(空($当前))
{
//如果我们达到这一点,$include仍然为true,则表示当前数组中没有子数组(否则,$include将为false,原因如下所示)
若有($包括)
$result[]=$index;
//注意!使用下面的命令,我们将$array恢复到它以前的级别…我们之前输入了一个子数组,现在我们将退出子数组并返回到上一级别,在那里中断的循环将继续
$array=array\u pop($array\u stack);
//对$index字符串执行相同的操作(返回一级)
$index=substr($index,0,strrpos($index,'.');
//如果我们返回一个级别,那么我们不希望在结果中包含先例数组…是吗?
$include=false;
}
//尝试从下面两行中删除注释!您将看到数组内容,因为如果不输入子数组或移出子数组,我们总是输入此“else”
//否则
//回显$index.'=>'.$current['value'].
'; } 返回$result; } $result=find_deep($my_数组); 打印(结果);
守则最重要的部分包括:

  • while
    循环中的
    每个
    命令
  • array\u push
    函数调用,我们将当前数组存储在“数组堆栈”中,以便稍后返回
  • array\u pop
    函数调用,通过从“数组堆栈”还原当前数组返回一级

  • RecursiveIteratorIterator
    知道所有子项的当前深度。由于您只对有子项的子项感兴趣,请筛选出没有子项的子项并查找最大深度

    然后根据深度再次过滤最大深度:

    $ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST);
    
    $cf = new ChildrenFilter($ritit);
    
    $maxdepth = NULL;
    foreach($cf as $v)
    {
        $maxdepth = max($maxdepth, $cf->getDepth());
    }
    
    if (NULL === $maxdepth)
    {
        throw new Exception('No children found.');
    }
    
    $df = new DepthFilter($cf, $maxdepth);
    
    foreach($df as $v)
    {
        echo "Array with highest depth:\n", var_dump($v), "\n";
    }
    

    /

    递归foreach函数,来自以下注释:

    请注意,上述实现会生成一个扁平阵列。要保留嵌套,请执行以下操作:

    function RecurseArray($inarray) {
        $result = array();
        foreach ( $inarray as $inkey => $inval ) {
            if ( is_array($inval) ) {
                $result[] = RecurseArray($inval);
            } else {
                // process $inval, store in result array
                $result[] = $inval;
            }
        }
    
        return $result;
    }
    
    要在位修改阵列,请执行以下操作:

    function RecurseArray(&$inarray) {
        foreach ( $inarray as $inkey => &$inval ) {
            if ( is_array($inval) ) {
                RecurseArray($inval);
            } else {
                // process $inval
                ...
            }
        }
    }
    
    定义 简单: 描述没有子表达式的表达式(例如“5”、“x”)。 化合物: 描述具有子表达式的表达式(例如“3+x”、“1+2”)。 常数: 表达式是否具有常量值(例如“5”、“1+2”)(例如“x”、“3+x”)。 外部节点: 在表达式树中,通过始终向左或向右遍历可到达的节点。“外部”始终相对于给定节点;节点可能相对于一个节点“外部”,但相对于该节点的父节点“内部”。 内部节点:function RecurseArray($inarray) { $result = array(); foreach ( $inarray as $inkey => $inval ) { if ( is_array($inval) ) { $result[] = RecurseArray($inval); } else { // process $inval, store in result array $result[] = $inval; } } return $result; }
    function RecurseArray(&$inarray) {
        foreach ( $inarray as $inkey => &$inval ) {
            if ( is_array($inval) ) {
                RecurseArray($inval);
            } else {
                // process $inval
                ...
            }
        }
    }
    
    __1__ / \ 2 5 / \ / \ 3 4 6 7
    array(
        '=' => array(
            '+' => array( // 5x + 3
                '*' => array(
                    5, 'x'
                ),
                3
            )
            '+' => array( // (x+(3+(5-3)))
                'x',
                '+' => array( // (3+(5-3))
                    3,
                    '-' => array(
                        5, 3
    )   )   )   )   )
    
    array(
        '=' => array(
            '+' => array( // 5x + 3
                '*' => array(
                    5, 'x'
                ),
                3
            )
            '+' => array( // x+3+5-3
                'x',
                3,
                '-' => array(
                    5, 3
    )   )   )   )
    
    simplify_expr(expression : Expression&, operation : Token) : Expression {
        if (is_array(expression)) {
            foreach expression as key => child {
                Replace child with simplify_expr(child, key); 
                    key will also need to be replaced if new child is a constant 
                    and old was not.
            }
            return simplify_node(expression, operation);
        } else {
            return expression;
        }
    }
    
    simplify_node(expression : Expression&, operation : Token) : Expression;
    
    + + + + / \ / \ / \ / \ \+ 2 ---> + 2 + y ---> + y / \ / \ / \ / \ 1 x x 1 x 1 1 x + + / \ / \ \+ c ---> a + / \ / \ a b b c Expression / \ SimpleExpr CompoundExpr / \ ConstantExpr VariableExpr
    Expression {
        isConstant:Boolean
        simplify():Expression
    }
    
    SimpleExpr < Expression {
        value:Varies
        /* simplify() returns an expression so that an expression of one type can 
           be replaced with an expression of another type. An alternative is
           to use the envelope/letter pattern:
             http://users.rcn.com/jcoplien/Patterns/C++Idioms/EuroPLoP98.html#EnvelopeLetter
             http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Envelope_Letter
         */
        simplify():Expression { return this }
    }
    
    ConstantExpr < SimpleExpr {
        isConstant:Boolean = true
    }
    
    VariableExpr < SimpleExpr {
        isConstant:Boolean = false
    }
    
    CompoundExpr < Expression {
        operation:Token
        children:Expression[]
    
        commutesWith(op:Expression):Boolean
        isCommutative:Boolean
        isConstant:Boolean = (){ 
            for each child in this.children:
                if not child.isConstant, return false
            return true
        }
        simplify():Expression {
            for each child& in this.children {
                child = child.simplify()
            }
            return this.simplify_node()
        }
        simplify_node(): Expression {
            if this.isConstant {
                evaluate this, returning new ConstExpr
            } else {
                if one child is simple {
                    if this.commutesWith(compound child)
                       and one grand-child doesn't match the constness of the simple child 
                       and the other grand-child matches the constness of the simple child 
                    {
                        if (compound child.isCommutative):
                            make odd-man-out among grand-children the outer child
                        rotate so that grand-children are both const or not
                        if grand-children are const:
                            set compound child to compound child.simplify_node()
                        }
                } else {
                    ...
                }
            }
            return this
        }
    }
    
    class SimpleExpr extends Expression {
        public $value;
        function __construct($value) {
            $this->value = $value;
        }
        function simplify() { 
            return $this;
        }
    }
    
    class ConstantExpr extends SimpleExpr {
        // Overloading
        function __get($name) {
            switch ($name) {
            case 'isConstant':
                return True;
            }
        }
    }
    
    function Expression {
        protected $_properties = array();
        // Overloading
        function __get($name) {
            if (isset($this->_properties[$name])) {
                return $this->_properties[$name]; 
            } else {
                // handle undefined property
                ...
            }
        }
        ...
    }
    
    class ConstantExpr extends SimpleExpr {
        function __construct($value) {
            parent::construct($value);
            $this->_properties['isConstant'] = True;
        }
    }