如何退出PHP中的数组迭代函数(array_reduce)
我有一个array_reduce函数,当满足特定条件时,我愿意退出该函数如何退出PHP中的数组迭代函数(array_reduce),php,arrays,loops,array-reduce,Php,Arrays,Loops,Array Reduce,我有一个array_reduce函数,当满足特定条件时,我愿意退出该函数 $result = array_reduce($input, function($carrier, $item) { // do the $carrier stuff if (/* god was one of us */) { break; //some break analogue } return $carrier; }); 我如何做到这一点?还是应该改用foreach?array\u re
$result = array_reduce($input, function($carrier, $item) {
// do the $carrier stuff
if (/* god was one of us */) {
break; //some break analogue
}
return $carrier;
});
我如何做到这一点?还是应该改用foreach?
array\u reduce
用于编写始终在整个数组上迭代的函数式代码。您可以重写以使用常规的foreach循环来实现短路逻辑,也可以简单地返回未修改的当前$carrier
。这仍然会在整个数组中进行迭代,但不会改变结果(正如您所说,这更类似于continue
)根据类似的答案。
完成此任务的最佳和最差方法是例外。
不建议采用这种方式,但这种方式可以解决您的问题:
try {
$result = array_reduce( $input, function ( $carrier, $item ) {
// do the $carrier stuff
$condition = true;
if ( $condition ) {
throw new Exception;
}
return $carrier;
} );
} catch ( Exception $exception ) {
echo 'Break';
}
我解决问题的方法
我将创建一个全局函数或编写PHP扩展并添加一个函数
关于编写PHP扩展,有一个很好的答案:
但破坏实现也有一个问题。
需要检测哪种情况不起作用。
在实现下面,array\u reduce\u 2
检查回调是否返回。
如果是这样,则中断执行
这种方法允许通过检查值的返回类型来检查执行是否中断
array\u reduce\u 2实现
根据@wordragon通知,实现了将关联数组作为param传递的功能
function array_reduce_2( $array, $callback, $initial = null ) {
$len = count( $array );
$index = 0;
if ( $len == 0 && count( func_get_args() ) == 1 ) {
return null;
}
$values = array_values( $array );
$result = $initial ?? $values[ $index ++ ];
foreach ( $values as $value ) {
$result = $callback( $result, $value );
if ( ! is_callable( $result ) ) {
continue;
}
// break;
return $result;
}
return $result;
}
我使用了JS实现的思想,并相应地重写了PHP
检测是否发生中断
重要的是要注意!
这个
array\u reduce\u 2
实现只有在您不需要返回正常值作为回调时才能正常工作。首先,让我说array\u reduce可能是我最喜欢的函数之一-我很出名(嗯,在一个很小的圈子里)获取40行清晰编写的代码,并将其替换为4行更难理解的10行数组。\u减少执行相同操作的调用
遗憾的是,PHP数组函数似乎注定要完成它们的任务。再加上无法生成递归的未命名函数,使得这种常见情况难以处理。我不想在我的代码中加入太多难看的for循环,我倾向于将它们埋在另一个函数中(参见下面的reduce),就像前面的海报一样
值得指出的是,这远不如使用数组函数有效,而且在大多数情况下,最好让数组reduce函数使用“done”标志快速旋转不需要的值。无论如何,这与array_reduce类似(求值函数使用null返回表示其已完成)。目标是将数组中的数字相加,直到得到4
<?php
$init = 0;
$arr = [1,2,3,4,5,6,7,8,9,0];
$func = function($c, $it) {
if ($it == 4) return null;
return $c + $it;
};
function reduce($arr, $f, $init) {
for ($c = $init; count($arr); ) {
$newc = $f($c, array_shift($arr));
if (!isset($newc)) break;
$c = $newc;
}
return $c;
}
echo reduce($arr, $func, $init) . "\n"; // 6
易碎数组\u reduce()
function breakable\u array\u reduce(数组$array,可调用$callback,$initial=null){
$result=$initial;
foreach($array作为$value){
$ret=$callback($result,$value);
如果(false==$ret){
返回$result;
}否则{
$result=$ret;
}
}
返回$result;
}
用法
//10个值的数组
$arr=[
1.
1.
1.
1.
1.
1.
1.
1.
1.
1.
];
//值>=5时停止的回调函数
$sum_until_five=函数($initial,$value){
如果($initial>=5){
返回false;
}否则{
返回$initial+$value;
}
};
//使用$sum_until_five()计算$arr的总和
$sum=易碎阵列减少($arr,$sum\u直到第五个);
//产出:5
echo$sum;
解释
breakable\u array\u reduce()
将像array\u reduce()
一样工作,除非/直到callback$callback
返回bool(false)
使用数组键的替代实现:
易碎数组\u减少键控()
function breakable\u array\u reduce\u keyed(数组$array,可调用$callback,$initial=null){
$result=$initial;
foreach($key=>$value的数组){
$ret=$callback($result,$value,$key);
如果(false==$ret){
返回$result;
}否则{
$result=$ret;
}
}
返回$result;
}
用法
//值数组
$arr=[
‘foo’=>1,
'bar'=>1,
‘baz’=>1
];
//当$key=='baz'时停止的回调函数
$sum_until_baz=函数($initial,$value,$key){
如果('baz'==$key){
返回false;
}否则{
返回$initial+$value;
}
};
//使用$sum_until_baz()计算$arr的总和
$sum=易碎阵列减少($arr,$sum_直到_baz);
//产出:2
echo$sum;
另外,我刚刚编写并在本地进行了全面测试。我建议改用foreach
循环。不使用array\u reduce
的原因如下:
合理理由:
它不是静态类型检查的。因此,如果输入或回调参数中存在任何类型错误,则代码检查不会显示类型错误
它返回mixed
,因此如果您误用结果,检查不会显示错误,如果您正确使用,检查可能会显示假阳性
你不能打破
自以为是的理由:
这对眼睛更难。拥有一个$result
并将其添加到循环中(或您所做的任何事情)要比理解某个内容是返回的ed,然后在下一次调用中作为$carry
累加器传递容易得多
它使我懒得正确地提取函数。如果我将一个操作提取到回调中,那么我可能会发现代码足够短,无法将整个数组操作提取到一个函数中,而这个函数实际上应该首先完成
如果您使用一个条件来中断,很可能有一天您需要该回调函数的其他参数。在回调签名被修复的情况下,您必须传递参数w
$input = [ 'test', 'array', 'god was one of us' ];
$result = array_reduce_2( $input, function ( $carrier, $item ) {
// do the $carrier stuff
if ( $item === 'god was one of us' ) {
return function () {
return 'god was one of us';
};
}
return $carrier;
} );
$is_break = is_callable( $result );
if ( $is_break ) {
echo $result();
exit;
}
<?php
$init = 0;
$arr = [1,2,3,4,5,6,7,8,9,0];
$func = function($c, $it) {
if ($it == 4) return null;
return $c + $it;
};
function reduce($arr, $f, $init) {
for ($c = $init; count($arr); ) {
$newc = $f($c, array_shift($arr));
if (!isset($newc)) break;
$c = $newc;
}
return $c;
}
echo reduce($arr, $func, $init) . "\n"; // 6