【问题标题】:php filter multidimensial array by multiple key values criteriaphp通过多个键值条件过滤多维数组
【发布时间】:2021-03-05 04:26:54
【问题描述】:

我正在使用库存数据库(是的,我知道这可能会使用 mysql 完成),但我目前最终得到了一个 php 数组

$products = array( array("id"=>"123", "sku"=>"MED_BL_DRESS", "size"=>"medium", "color"=>"black"),
            array("id"=>"321", "sku"=>"LG_GR_DRESS", "size"=>"large", "color"=>"green"),
            array("id"=>"31321", "sku"=>"LG_RD_DRESS", "size"=>"large", "color"=>"red")
);

用户会选择一个尺寸,我要传入函数:

 filterArray($products, array("size"=>"medium")) 

我希望我能得到一个数组,只有符合该条件的记录...如果我通过了多个条件,那么问题就来了,

 filterArray($products, array("size"=>"medium", "color"=>"black"))  

然后数组会给我一个产品数组,其中只有一个产品在数组中匹配。我正在尝试构建它,以便我可以在 products 数组中拥有任意数量的键值(也许有些产品将“性别”作为过滤器,而另一些则不会。它可能有很多过滤器变体。

我尝试循环遍历数组并暴力破解它,但我认为必须有一种比一堆嵌套递归函数更优雅的方法。

【问题讨论】:

标签: php arrays function


【解决方案1】:

为什么觉得这么难? 不需要递归。

此答案假设您希望所有结果都通过 AND 逻辑匹配。您还可以扩展 filter 函数以使用第二个数组进行 OR 逻辑。在 ElasticSearch 中有一个必须和应该的术语。

  • 第一个将找到所有尺寸“大”
    (两个结果)
  • 第二个会找到所有尺寸“大”和颜色“绿色”
    (一个结果)

过滤器说明

  • 密钥计数器用于了解产品必须匹配多少个密钥
  • 外循环会遍历所有产品
  • 对于每次迭代,匹配计数器重置为 0
  • 然后将过滤器中有多少匹配项与当前产品进行比较
  • 当匹配等于 keycount 时,所有过滤器都通过了正数并将乘积添加到结果中。
$products = [
    ["id" => "123", "sku" => "MED_BL_DRESS", "size" => "medium", "color" => "black"],
    ["id" => "321", "sku" => "LG_GR_DRESS", "size" => "large", "color" => "green"],
    ["id" => "31321", "sku" => "LG_RD_DRESS", "size" => "large", "color" => "red"]
];

print_r(filterArray($products, ['size' => 'large']));
print_r(filterArray($products, ['size' => 'large', 'color' => 'green']));

function filterArray(array $products, array $filter = []): array
{
    $result = [];
    $keyCount = count($filter);
    foreach ($products as $product) {
        $match = 0;
        foreach ($filter as $key => $value)
            if ($product[$key] === $value) $match++;
        if ($match === $keyCount) $result[] = $product;
    }
    return $result;
}

【讨论】:

    【解决方案2】:

    您可以为此使用array_filter。此外,您可以传递一个额外的参数来指示该行是否必须匹配 all 过滤器,或者它是否可以匹配 any 过滤器以使函数更加动态和有用:

    Working example

    /**
     * @param array $products
     * @param array $filters
     * @param bool $matchAll
     * @return array
     */
    function filterArray(array $products, array $filters, bool $matchAll = true): array
    {
        return array_filter($products, static function($product) use ($filters, $matchAll) {
            $matches     = 0;
            $filterCount = count($filters);
            foreach ($filters as $filterColumn => $filterValue) {
    
                if (isset($product[$filterColumn]) && $product[$filterColumn] === $filterValue) {
                    $matches++;
                    if (!$matchAll) {
                        break;
                    }
                }
            }
            return  ($matches && !$matchAll) || ($matchAll && ($matches === $filterCount));
        });
    }
    
    
    $products = [
        ["id"=>"123", "sku"=>"MED_BL_DRESS", "size"=>"medium", "color"=>"black"],
        ["id"=>"321", "sku"=>"LG_GR_DRESS", "size"=>"large", "color"=>"green"],
        ["id"=>"31321", "sku"=>"LG_RD_DRESS", "size"=>"large", "color"=>"red"]
    ];
    
    
    
    // Filter matching all filters
    $filters = ["size"=>"medium", "color"=>"black"];
    $filteredProducts = filterArray($products, $filters);
    var_dump($filteredProducts);
    
    
    
    // Filter matching any of the filters
    $filters = ["size"=>"medium", "color"=>"black",  "sku"=>"LG_RD_DRESS"];
    $filteredProducts = filterArray($products, $filters, false);
    var_dump($filteredProducts);
    

    【讨论】:

      【解决方案3】:

      此解决方案使用array_filter() 函数。在回调函数中,array_intersect_assoc() 用于检查 $filter 数组的所有元素是否都存在于该行中。

      function filterArray(array $products, array $filter = []): array
      {
        return array_filter(
          $products, 
          function($row) use($filter){
            return array_intersect_assoc($filter, $row) === $filter;
          }
        );
      }
      

      【讨论】:

        猜你喜欢
        • 2019-11-28
        • 2019-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-04
        • 2018-07-07
        相关资源
        最近更新 更多