【问题标题】:PHP opposite of array_filter?与array_filter相反的PHP?
【发布时间】:2017-02-01 07:00:53
【问题描述】:

我熟悉array_filter,并且我正在尝试更多功能,但我想知道是否有办法保留丢弃的值?例如,如果我有一个像这样的数组:

<?php  
  $arr = array( 1, 2, 3, 4 );
  $arrGreaterThanTwo = array_filter($arr, function($item){
   return $item > 2;
 });

结果将是:array(3, 4)。

  1. 有没有办法保留丢弃的值数组(1、2)?
  2. 或者我是否需要在原始数组上再次重用 array_filter 并将 item
  3. 如果我再次使用 array_filter 来抓取 array( 1, 2 ),那么通过两次循环原始数组会不会效率低下?

最后,我只是想用 array_filter 循环一次,并将丢弃的值也保存到一个单独的数组中。

提前致谢!

【问题讨论】:

  • 只需使用带有 if/else 条件的简单 foreach 循环,然后您可以将满足您条件的元素添加到一个数组中,将其余元素添加到另一个数组中。
  • 过滤数组。这就是它在盒子里说的,这就是它的作用。只需使用 foreach 循环。
  • 循环两次不会低效。试试吧。测试执行时间。

标签: php arrays functional-programming


【解决方案1】:

如果您想获取过滤后的其他数组值,请使用array_diff()

array_diff — 计算数组的差异

$arrRemaining = array_diff($arr, $arrGreaterThanTwo);

输出:

Array
(
  [0] => 1
  [1] => 2
)

【讨论】:

  • 我喜欢这个答案,因为它简单、干净且易于理解。但是,如果我错了,请纠正我......这是循环两次。我将对自己的问题进行破解,看看其他开发人员的想法。非常感谢您的回答。
【解决方案2】:
function array_partition(array $array, callable $fn){
    $result = [[],[]];
    foreach ( $array as $value ){
        $result[$fn($value)?0:1][]=$value;
    }
    return $result;
}
// example usage:
$res = array_partition([1,2,3,4,5,6,7,8,9,10], function($i) { return $i&1==1;});

虽然这不是函数式实现,但它有一个函数式接口,就像array_filter。

【讨论】:

  • 有趣……一个全新的思考过程……让我大吃一惊。不得不读几遍。
  • Wups,在提交之前我没有阅读您的回复。 A+ 作品,西尔维斯特 ^_^
  • @naomik 谢谢。我很惊讶 PHP 没有包含这个。
  • 我接受这个作为答案;但是,我也喜欢@Object Manipulator 的答案,因为它更简洁易懂。对象操纵器答案的唯一缺点是它循环了两次。归根结底,这是可以理解的/可维护性与效率的对比。这个答案更有效率。
【解决方案3】:

我可能会建议您为它编写自己的函数。这是array_bifilter——它不是返回一个数组,而是返回两个。第一个是 truthy 值,第二个是 falsey 值。是的,它只遍历输入数组一次。

function array_bifilter(array $xs, callable $f) {
  return array_reduce($xs, function ($acc, $x) use ($f) {
    if (call_user_func($f, $x))
      array_push($acc[0], $x);
    else
      array_push($acc[1], $x);
    return $acc;
  }, [[], []]);
}

list($t, $f) = array_bifilter([1,2,3,4], function($x) { return $x > 2; });

echo json_encode(['true' => $t, 'false' => $f], JSON_PRETTY_PRINT), PHP_EOL;

输出(JSON 格式,便于阅读)

{
    "true": [
        3,
        4
    ],
    "false": [
        1,
        2
    ]
}

【讨论】:

    【解决方案4】:

    更新回复

    function test($arrOne, $fn){
      $restArr = [];
    
      $filterResults = array_filter($arrOne, function($item) use (&$restArr, $fn) {
          if( $fn($item) ) return $item;
          $restArr[] = $item;
      });
    
      return array( $filterResults, $restArr );
    }
    
    print_r( test( array(1,2,3,4), function($item){
      return $item > 2;
    } ) );
    

    有人对此有意见吗?

    【讨论】:

    • 是的,问题是$restArr 的全局范围。最好不要使用全局变量,因为副作用通常会产生难以调试的代码。这个想法不错,但 Sylwester 的建议要干净得多。
    • 感谢您的回复。这是有道理的。
    • @CamilStaps 如果我将它包装到它自己的方法或函数中并返回两个数组呢?尽管 $restArr 是全局的,但它只是方法内部的“全局”。
    • 它有效,但它仍然是一种非常不清楚的方法。想象一下一年后回到这个问题,是否清楚这段代码的作用?应该避免使用全局变量,不仅因为副作用会产生无法调试的错误,而且因为它们使代码更难理解。作为旁注,(我认为)&amp;$restArr 可能只是$restArr,use 永远不会通过值传递某些东西(未经测试)。
    • 我不知道,但我发现 Sylwester 的答案比这个更难阅读。如果您只传递 $restArr 而不传递 &,则 $restArr 将为空。我真的没有看到传递 &$restArr 因为在函数内部的危害。如果是在外面,那就是……呸……也许是我不明白。
    猜你喜欢
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 2013-05-31
    • 2011-07-25
    • 1970-01-01
    • 2011-11-19
    • 1970-01-01
    • 2012-01-29
    相关资源
    最近更新 更多