从foreach中的数组中取消设置元素 [英] Unsetting elements from array within foreach

查看:155
本文介绍了从foreach中的数组中取消设置元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在开发一个通用的表单创建类,昨天有个问题。
我做了一个片段来重现这个问题。

基本上我想删除整个组被绘制之后从原始元素数组中分组的元素,我正在循环元素数组。



代码片段应该涵盖这个问题,我在这里错过了什么吗?从我的知识删除一个元素,而foreach是完全安全和合法的,因为foreach内部只使用一个副本,可能会在循环中修改。

  $ ids = array('a'=> array(),'b'=> array(),'c'=> array()); 
$ groups ['g1'] = array('a','c');
foreach($ ids as $ id => $ element){

// var_dump($ ids);
$ g_id ='';
$ b $ //搜索所有组中的id
foreach($ groups as $ group_id => $ group){
if(in_array($ id,$ group)){
$ g_id = $ group_id;
break;


$ b $ //元素是组
的一部分if($ g_id!==''){

/ / echo $ g_id;

//元素a和c在循环中被取消设置,不应该在$ ids中
foreach($ groups [$ g_id]作为$ field_id){
unset($ IDS [$ FIELD_ID]);

echo $ field_id;
}
unset($ groups [$ g_id]);
} else {
if($ id ==='a'|| $ id ==='c')
echo $ id;




元素'c'在foreach中被取消设置..)循环,然后在else分支中再次输出。另外,当我var_dump($字段)在开始时,我总是得到'a','b'和'c'里面。我使用PHP 5.4.7。

提前致谢

编辑:我在示例代码,现在更新。所有有关使用错误的索引(它应该是0,1等)的评论当然是正确的。
使用var_dump的值现在是未设置的,但是我仍然使用'c'来进入else。


编辑2:
使用原始代码完成,但通过阅读意见后,我目前提出了以上解决方案的以下张贴代码片段:



  $ IDS =阵列( A=>阵列()中, b=>阵列(), C=>阵列(), d=>阵列(), E=>阵列()); 
$ groups = array(array(a),array(c,e));
array_walk($ groups,function($ v,$ i)use(& $ ids){

$ in_both = array_intersect(array_keys($ ids),$ v);
// var_dump($ in_both);
foreach($ in_both as $ b){
unset($ ids [$ b]);
}
});
print_r($ ids);

  $ IDS =阵列( A=>阵列()中, b=>阵列(), C=>阵列(), d=>阵列(), E=>阵列()); 
$ groups = array(array(a),array(c));
array_walk($ ids,function($ v,$ i)use(& $ ids,$ groups){
$ in_both = array();
foreach($ groups as $ g ){
if(in_array($ i,$ g)){
$ in_both = array_intersect(array_keys($ ids),$ g);
}
}

foreach($ in_both as $ b){
unset($ ids [$ b]);
}
});
print_r($ ids);

在这种情况下使用foreach不适用于我,因为我需要更改$ ids数组而循环迭代它。

在最基本的情况下,代码如下:

  $ ids = array('a','b'); 

while(count($ ids)){
array_pop($ ids);
echo'pop';
}

echo'empty';

虽然foreach可以改变数组的原始值,但不会改变数组的副本迭代已经说明了nl-x。
感谢Passerby为此使用array_walk的想法。

编辑3:
更新后的代码再次被剪切。第二个剪辑allthough表现也不明确。克里斯,如果我理解正确,你不要不要指望'C'在else分支输出吗?

但应该输出。你的逻辑是:


  • 你做foreach ID并以id开始。
  • 然后
  • 您从id 清除id a和c,并删除包含a的组g1 。在这个步骤中,删除的ID将被输出,是a和c。 (清除id和c将不会影响 foreach($ id为$ id),因为foreach将继续使用未触及的副本在清除ids数组后。)
  • 然后你做id'b':它在任何组中都找不到。 (实际上,现在还没有剩下任何组)。

  • 所以对于'b'你输入else分支。但是else分支中的if()可以防止输出

  • ,那么你可以使用id'c',这在任何组中都找不到,因为你已经删除了组g1 !还有没有组,还记得吗?

  • 所以对于'c'你也可以输入else分支。这次else分支中的if()允许输出!输出只是c


    因此总输出确实是acc。

    知道一个foreach(),即使在其元素被清除后仍然保留着一个未触及的拷贝,这是一个特定的PHP事情。其他语言不一定要这样做。


    I'm currently working on a generic form creation class and had an issue yesterday. I made a snippet to reproduce the problem.

    Essentially I want to delete elements that are grouped from the original elements array after the whole group has been drawn and I'm doing this while looping over the elements array.

    The code snippet should cover the problem, am I missing something here? From my knowledge deleting an element while foreach is completely safe and legal since foreach internally only uses a copy that may be modified during the loop.

    $ids = array('a' => array(), 'b' => array(), 'c' => array());
    $groups['g1'] = array('a', 'c');
    foreach($ids as $id => $element) {
    
        //var_dump($ids);
        $g_id = '';
    
        // search the id in all groups
        foreach($groups as $group_id => $group) {
            if(in_array($id, $group)) {
                $g_id = $group_id;
                break;
            }
        }
    
        // element is part of a group
        if($g_id !== '') {
    
            //echo $g_id;
    
            // element a and c gets unset within loop and should not be in $ids anymore
            foreach($groups[$g_id] as $field_id) {
                unset($ids[$field_id]);
    
                echo $field_id;
            }
            unset($groups[$g_id]);
        } else {
            if($id === 'a' || $id === 'c')
                echo $id;   
        }
    }
    

    Element 'c' gets unset within the foreach(groups ..) loop but is afterwards again outputted in the else branch. Also when i var_dump($fields) at the beginning i always get 'a', 'b' and 'c' inside. I'm using PHP 5.4.7.

    Thanks in advance

    EDIT: i made a mistake in the sample code, its now updated. All comments about using the wrong index (it would have been 0,1 etc) were correct of course. The values when using var_dump are unset now, but i still get into the else with 'c' one time.

    EDIT2: Im not done with the original code but after reading through the comments I currently came up with following solution to the posted code snippet above:

    $ids=array("a"=>array(),"b"=>array(),"c"=>array(),"d"=>array(),"e"=>array());
    $groups=array(array("a"),array("c", "e"));
    array_walk($groups,function($v,$i)use(&$ids){
    
        $in_both = array_intersect(array_keys($ids),$v);
        //var_dump($in_both);
        foreach($in_both as $b) {
            unset($ids[$b]);
        }
    });
    print_r($ids);
    

    or

    $ids=array("a"=>array(),"b"=>array(),"c"=>array(),"d"=>array(),"e"=>array());
    $groups=array(array("a"),array("c"));
    array_walk($ids,function($v,$i)use(&$ids, $groups){
        $in_both = array();
        foreach($groups as $g) {
            if(in_array($i,$g)) {
                $in_both = array_intersect(array_keys($ids),$g);
            }
        }
    
        foreach($in_both as $b) {
            unset($ids[$b]);
        }
    });
    print_r($ids);
    

    Using a foreach does not work for me in this case, because i need to change the $ids array while the loop is iterating over it.

    In the very most basic situation a code something like this:

    $ids = array('a', 'b');
    
    while(count($ids)) {
        array_pop($ids);
        echo 'pop';
    }
    
    echo 'empty';
    

    Allthough foreach can change the original values from the array it will not change the copy of the array used for the iteration as nl-x already stated. Thanks to Passerby for the idea of using array_walk for this.

    EDIT3: Updated code snipped once more. The second snipped allthough behaves undefined as well. Deleting elements from an array while iterating over its seems to be a bad idea.

    解决方案

    Chris, if I understand correctly, you don't expect 'C' to be outputted in the else branch?

    But it should be outputted. Your logic is:

    • you do foreach ids and start with id 'a'.
    • then you clear ids a and c from ids and delete the group g1 that contained 'a'. During this step the deleted ids will be outputted, being a and c. (Clearing a and c from ids will have no impact on the foreach($ids as $id) as foreach will continue with the untouched copy even after ids array has been cleared.)
    • then you do id 'b': it is not found in any group. (actually, there isn't any group left by now anyway)
    • so for 'b' you enter the else branch. But the if() inside the else branch prevents output
    • then you do id 'c', which is also not found in any group, because you have already deleted group g1! There are no groups left, remember?
    • so for 'c' you also enter the else branch. And this time the if() inside the else branch allows the output! The output being just c

    So the total output is indeed acc.

    It is good to know that a foreach() that continues with a untouched copy even after its elements were cleared, is a specific PHP thing. Other language do no necessarily do the same.

    这篇关于从foreach中的数组中取消设置元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆