【问题标题】:PHP array_filter on OR operator或运算符上的 PHP array_filter
【发布时间】:2021-09-14 18:04:11
【问题描述】:

我正在使用array_filter 将过滤器数组应用于数据数组。函数调用看起来像
$data = array_filter($tmpData, function($row) use $filterData { ... });
如果我在每个过滤器的逻辑为 AND 的位置进行过滤,这很好用。但是,如果我想使用 OR 在两个值之间进行过滤,那么我对如何处理这个问题会有些犹豫,因为每个过滤器还可以有一组嵌套的更多过滤器,这些过滤器会递归地调用过滤函数。过滤器的格式如下:

$filter = array(
  'logic' => 'AND',
  'filters' => array(
    array('field' => $myFieldName1, 'operator' => $filterOperator1, 'value' => $myValue1),
    array(
      'logic' => 'OR',
      'filters' => array(
        array('field' => $myFieldName2, 'operator' => $filterOperator2, 'value' => $myValue2),
        array('field' => $myFieldName3, 'operator' => $filterOperator3, 'value' => $myValue3)
      )
    )
  )
);

您可以在此处看到我的函数的略微精简版本。除了“等于”之外,它只实现了一个过滤运算符。 https://www.tehplayground.com/FiPHxwDNJWdKq4hM

感谢您对完成这项工作的 OR 部分的任何帮助。

【问题讨论】:

    标签: php filtering array-filter


    【解决方案1】:

    我认为递归函数会让你到达那里。首先,我将模拟一些与您的数据相似但可能更简单的数据:

    $obj = new stdClass();
    $obj->a = 5;
    $obj->b = 2;
    $obj->c = 9;
    
    $filter = array(
        'logic' => 'AND',
        'filters' => array(
            array('field' => 'a', 'operator' => '===', 'value' => 5),
            array(
                'logic' => 'OR',
                'filters' => array(
                    array('field' => 'b', 'operator' => '===', 'value' => 6),
                    array('field' => 'c', 'operator' => '<', 'value' => 10),
                ),
            ),
        ),
    );
    

    然后,我们正在编写一个递归函数。我使用的是 PHP 8 的 match,这使得这非常简洁,但您可能需要根据您的 PHP 版本进行更改。有关详细信息,请参阅代码 cmets。这不是最有效的,但应该可以完成工作。

    function process(string $logic, array $filters, object $obj): bool
    {
        // For an AND, all things must be true, so if we're given 5 things, all 5 must be true.
        // For an OR, only one needs to be true.
        $targetCount = 'AND' === $logic ? count($filters) : 1;
    
        // How many items were true
        $currentCount = 0;
        foreach ($filters as $filter) {
    
            // The sub-array is a grouping, grab parts, process, and if true, increment our local counter
            if (array_key_exists('logic', $filter)) {
                if (process($filter['logic'], $filter['filters'], $obj)) {
                    $currentCount++;
                }
    
                // For a sub-array, don't process anything else
                continue;
            }
    
            // Grab array items as variables just for ease of use
            $field = $filter['field'];
            $operator = $filter['operator'];
            $value = $filter['value'];
    
            // Match on the operator. For lower versions of PHP a switch(true) or just an if could be used, too.
            $result = match ($operator) {
                '===' => $obj->$field === $value,
                '==' => $obj->$field == $value,
                '>=' => $obj->$field >= $value,
                '>' => $obj->$field > $value,
                '<=' => $obj->$field <= $value,
                '<' => $obj->$field < $value,
            };
    
            // If success, increment our counter
            if ($result) {
                $currentCount++;
    
                // If we've reach our target, return success
                // This could also just be "if process = OR"
                if ($currentCount === $targetCount) {
                    return true;
                }
            }
        }
    
        // See if we met the final condition outside of the loop
        return $currentCount === $targetCount;
    }
    

    最后,一个调用它的例子。使用递归函数,您通常必须确定是否要让整个函数尝试并确定它是否是第一次迭代并设置好东西,或者是否要传入设置以便每次迭代运行相同,我后者做了。

    echo process($filter['logic'], $filter['filters'], $obj) ? 'yes' : 'no';
    

    在线示例在这里:https://3v4l.org/Hu0CY#v8.0.8

    【讨论】:

      猜你喜欢
      • 2012-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 2011-08-21
      • 2010-12-31
      相关资源
      最近更新 更多