Php 删除数组_walk()中回调函数中的行
我尝试使用array_walk()函数处理数组,方法如下:Php 删除数组_walk()中回调函数中的行,php,arrays,Php,Arrays,我尝试使用array_walk()函数处理数组,方法如下: <?php $array = array('n1' => 'b1', 'n2' => 'b2', 'n3' => 'b3'); array_walk($array, function(&$val, $key) use (&$array){ echo $key."\n"; if ($key == 'n1') $val = 'changed_b1'; if
<?php
$array = array('n1' => 'b1', 'n2' => 'b2', 'n3' => 'b3');
array_walk($array, function(&$val, $key) use (&$array){
echo $key."\n";
if ($key == 'n1')
$val = 'changed_b1';
if ($key == 'n2' || $key == 'n3') {
unset($array[$key]);
}
});
print_r($array);
看起来,删除第二个元素后——第三个元素不会被发送到回调函数 来自:
只有数组的值可能被更改;其结构不能更改,即程序员不能添加、取消设置或重新排序元素。如果回调不遵守此要求,则此函数的行为未定义,不可预测
这可能就是为什么您的代码不能获得所需输出的原因。希望能有帮助
可能的替代方案:
array\u walk()
,只需创建一个新数组,并将“必需”元素(即不希望删除的索引)复制到新数组中即可。如果要删除的元素数量非常大,这是首选的替代方案回调。您可以简单地在那里设置一个条件,禁止在此回调函数中删除索引。如果要删除的元素数量非常少,这将起作用
旁注-我没有加入任何代码片段,因为我已经链接了相关文档,开始使用它们本身应该是一个很好的练习。你可以做的是使用一个辅助数组,这将产生删除这些节点的效果,如
<?php
$array = array('n1' => 'b1', 'n2' => 'b2', 'n3' => 'b3');
$arrFinal = array();
array_walk($array, function($val, $key) use (&$array, &$arrFinal){
echo $key."\n";
if ($key == 'n2' || $key == 'n3') {
//Don't do anything
} else {
$arrFinal[$key] = $val;
}
});
print_r($arrFinal);
使用数组过滤器:
<?php
$filtered = array_filter($array, function($v,$k) {
return $k !== "n2" && $k !== "n3";
}, ARRAY_FILTER_USE_BOTH);
?>
参见我意识到这已经有好几年的历史了,但我在寻找类似情况的解决方案时发现了这条线索
最后,我使用preg_grep只返回我想要遍历的数组,以防有人发现它有用
因此,在我的例子中,我想忽略带有“.”前缀的scandir数组中的文件(系统文件),然后对其余文件应用新前缀
以下是我的结论:
$fl = array_map(function($i){
return $new_prefix . "/" . $i;
}, preg_grep("/^[^\.]/", scandir($path)));
如果您可以构建一个正则表达式来排除不需要的数组元素,那么这个解决方案应该可以工作。检查“array\u walk”源代码,您将看到。array_walk使用pos获取项目,在每个循环中,pos向前移动
do {
/* Retrieve value */
zv = zend_hash_get_current_data_ex(target_hash, &pos);
/* Retrieve key */
zend_hash_get_current_key_zval_ex(target_hash, &args[1], &pos);
/* Move to next element already now -- this mirrors the approach used by foreach
* and ensures proper behavior with regard to modifications. */
zend_hash_move_forward_ex(target_hash, &pos);
/* Back up hash position, as it may change */
EG(ht_iterators)[ht_iter].pos = pos;
并重置pos以获取值
/* Reload array and position -- both may have changed */
if (Z_TYPE_P(array) == IS_ARRAY) {
pos = zend_hash_iterator_pos_ex(ht_iter, array);
target_hash = Z_ARRVAL_P(array);
} else if (Z_TYPE_P(array) == IS_OBJECT) {
target_hash = Z_OBJPROP_P(array);
pos = zend_hash_iterator_pos(ht_iter, target_hash);
} else {
php_error_docref(NULL, E_WARNING, "Iterated value is no longer an array or object");
result = FAILURE;
break;
}
- 如果key=n1;然后下一个位置1
- 如果键=n2;然后下一个位置2
- 如果键=n3;然后下一个位置3
当运行[$key=='n2']时,下一个pos为2;取消设置后,无法到达位置2,因此循环结束
因此,实际上,$key=='n3'将不会发生,而u将得到结果。手册中有一个关于更改结构/取消设置thru array walk函数的重要说明,@Ghost,有没有解决问题的建议?请查看下面hd的答案,或者为什么不直接使用foreach?实际上,这段代码非常复杂,如果您只想得到一个没有特定键的数组,请使用unset($array[“n2”],$array[“n3”]);当您添加了一个很好的解释(从手册中引用)时,请使用另一个选项作为备份well@mochalygin,请参阅我的更新答案,以了解可能的替代方案。希望它能让您从正确的方向开始。值得一提的是,它适用于PHP>=5.6。x@m6w6,需要更改一些元素并取消设置一些元素--这样array\u filter()
can;这似乎是一个累赘,但如果没有其他建议,我会接受的。
/* Reload array and position -- both may have changed */
if (Z_TYPE_P(array) == IS_ARRAY) {
pos = zend_hash_iterator_pos_ex(ht_iter, array);
target_hash = Z_ARRVAL_P(array);
} else if (Z_TYPE_P(array) == IS_OBJECT) {
target_hash = Z_OBJPROP_P(array);
pos = zend_hash_iterator_pos(ht_iter, target_hash);
} else {
php_error_docref(NULL, E_WARNING, "Iterated value is no longer an array or object");
result = FAILURE;
break;
}