简体   繁体   English

从多维数组中删除深层嵌套的元素?

[英]Remove deeply nested element from multi-dimensional array?

I need to remove an element form a deeply nested array of unknown structure (ie I do not know what the key sequence would be to address the element in order to unset it). 我需要从一个未知结构的深层嵌套数组中删除一个元素(即,我不知道要取消设置该元素的键序列是什么)。 The element I am removing however does have a consistent structure (stdObject), so I can search the entire multidimensional array to find it, but then it must be removed. 但是,我要删除的元素确实具有一致的结构(stdObject),因此我可以搜索整个多维数组以找到它,但是必须将其删除。 Thoughts on how to accomplish this? 关于如何做到这一点的想法?

EDIT: This is the function I have right now trying to achieve this. 编辑:这是我现在试图实现此功能。

function _subqueue_filter_reference(&$where)
{
    foreach ($where as $key => $value) {
        if (is_array($value))
        {
            foreach ($value as $filter_key => $filter)
            {
                if (isset($filter['field']) && is_string($filter['field']) && $filter['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
                {
                    unset($value[$filter_key]);
                    return TRUE;
                }
            }
            return _subqueue_filter_reference($value);
        }
    }
    return FALSE;
}

EDIT #2: Snipped of array structure from var_dump . 编辑#2:var_dump剪切数组结构。

array (size=1)
  1 => 
    array (size=3)
      'conditions' => 
        array (size=5)
          0 => 
            array (size=3)
              ...
          1 => 
            array (size=3)
              ...
          2 => 
            array (size=3)
              ...
          3 => 
            array (size=3)
              ...
          4 => 
            array (size=3)
              ...
      'args' => 
        array (size=0)
          empty
      'type' => string 'AND' (length=3)

...so assuming that this entire structure is assigned to $array , the element I need to remove is $array[1]['conditions'][4] where that target is an array with three fields: ...因此,假设将整个结构分配给$array ,我需要删除的元素是$array[1]['conditions'][4] ,其中该目标是一个具有三个字段的数组:

  • field 领域
  • value
  • operator 算子

...all of which are string values. ...所有都是字符串值。

This is just a cursor problem. 这只是一个游标问题。

function recursive_unset(&$array)
{
    foreach ($array as $key => &$value) # See the added & here.
    {
        if(is_array($value))
        {
            if(isset($value['field']) && $value['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
            {
                unset($array[$key]);
            }
            recursive_unset($value);
        }
    }
}

Notes : you don't need to use is_string here, you can just make the comparison as you're comparing to a string and the value exists. 注意:此处不需要使用is_string,只需在与字符串进行比较时就可以进行比较,并且该值存在。

Don't use return unless you're sure there is only one occurrence of your value. 除非您确定只有一次出现您的价值,否则不要使用return。

Edit : 编辑:

Here is a complete example with an array similar to what you showed : 这是一个完整的示例,其数组类似于您显示的内容:

$test = array (
        1 => array (
                'conditions' =>
                array (
                        0 => array ('field' => 'dont_care1', 'value' => 'test', 'operator' => 'whatever'),
                        1 => array ('field' => 'dont_care2', 'value' => 'test', 'operator' => 'whatever'),
                        2 => array ('field' => 'nodequeue_nodes_node__nodequeue_subqueue.reference', 'value' => 'test', 'operator' => 'whatever'),
                        3 => array ('field' => 'dont_care3', 'value' => 'test', 'operator' => 'whatever')
                ),
        'args' => array (),
        'type' => 'AND'
));

var_dump($test);

function recursive_unset(&$array)
{
    foreach ($array as $key => &$value)
    {
        if(is_array($value))
        {
            if(isset($value['field']) && $value['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
            {
                unset($array[$key]);
            }
            recursive_unset($value);
        }
    }
}

recursive_unset($test);

var_dump($test);

One way to solve this was to extend your recursive function with a second parameter: 解决此问题的一种方法是使用第二个参数扩展递归函数:

function _subqueue_filter_reference(&$where, $keyPath = array())

You'd still do the initial call the same way, but the internal call to itself would be this: 您仍然可以用相同的方式进行初始调用,但是内部调用本身是这样的:

return _subqueue_filter_reference($value, array_merge($keyPath, array($key)));

This would provide you with the full path of keys to reach the current part of the array in the $keyPath variable. 这将为您提供键的完整路径,以到达$keyPath变量中数组的当前部分。 You can then use this in your unset . 然后,您可以在未unset使用它。 If you're feeling really dirty, you might even use eval for this as a valid shortcut, since the source of the input you'd give it would be fully within your control. 如果您真的很脏,您甚至可以使用eval作为有效的快捷方式,因为您输入的输入源将完全在您的控制之内。

Edit: On another note, it may not be a good idea to delete items from the array while you're looping over it. 编辑:另一方面,当您遍历数组时,从数组中删除项目可能不是一个好主意。 I'm not sure how a foreach compiles but if you get weird errors you may want to separate your finding logic from the deleting logic. 我不确定foreach的编译方式,但是如果遇到奇怪的错误,您可能希望将查找逻辑与删除逻辑分开。

I have arrived at a solution that is a spin-off of the function found at http://www.php.net/manual/en/function.array-search.php#79535 ( array_search documentation). 我已经找到了一个解决方案,该解决方案是从http://www.php.net/manual/en/function.array-search.php#79535(array_search文档)中找到的函数的array_search

Code: 码:

function _subqueue_filter_reference($haystack,&$tree=array(),$index="")
{
    // dpm($haystack);
    if (is_array($haystack))
    {

        $result = array();

        if (count($tree)==0)
        {
            $tree = array() + $haystack;
        }

        foreach($haystack as $k=>$current)
        {
            if (is_array($current))
            {
                if (isset($current['field']) && is_string($current['field']) && $current['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
                {
                    eval("unset(\$tree{$index}[{$k}]);"); // unset all elements = empty array
                }
                _subqueue_filter_reference($current,$tree,$index."[$k]");
            }
        } 
    } 
    return $tree;
}

I hate having to use eval as it SCREAMS of a giant, gaping security hole, but it's pretty secure and the values being called in eval are generated explicitly by Drupal core and Views. 我讨厌使用eval,因为它是一个巨大的,巨大的安全漏洞的SCREAMS,但它非常安全,并且eval中调用的值是由Drupal核心和Views显式生成的。 I'm okay with using it for now. 我现在可以使用它了。

Anyway, when I return the tree I simply replace the old array with the newly returned tree array. 无论如何,当我返回树时,我只是用新返回的树数组替换了旧的数组。 Works like a charm. 奇迹般有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM