用于数组值的数组过滤器

我有这段代码可以完成搜索选项名称的工作,如何使用它从数组中搜索选项值。

$productspp ='[{
    "id": 4674388066436,"title": "1st march","options": [{
        "id": 6046836162692,"product_id": 4674388066436,"name": "Size","position": 1,"values": ["12","24","36"]
    },{
        "id": 6067871875204,"name": "z","position": 2,"values": ["blue","green"]
    },{
        "id": 6067871907972,"name": "Material","position": 3,"values": ["silk","cotton"]
    }],},{
    "id": 4674394325124,"title": "2nd march","options": [{
        "id": 6046844190852,"product_id": 4674394325124,"name": "Title","values": ["Default Title"]
    }],{
    "id": 4679851704452,"title": "3rd marchhh","options": [{
        "id": 6053112545412,"product_id": 4679851704452,"values": ["Default Title"]
    }]
}]';

$array = json_decode($productspp,1);

    $filter_name555 ='options';
    $dummytstt ='values';
    $filter_value=  blue;


 $expected = array_filter($array,function($el) use ($filter_name555,$dummytstt,$filter_value) {

    return ( stripos($el[$filter_name555][0][$dummytstt],$filter_value) !== false ); 
}

}); 

如果用户搜索了option_value并且匹配,则应列出该产品,因此在这种情况下,如果用户搜索Silk,则应列出该产品,否则就不列出

对于选项名称,它适用于选项值,它不起作用,因为stripos期望它是字符串,但是在数据中,它是数组。

我们也尝试了in_array进行过滤,但这也没有效果

当我们搜索12或24或36或蓝色或绿色之类的内容时,它应该列出json的这一部分。我的意思是该产品和上面给出的代码相同,只是选项名称相同。您可以看到选项值是数组。它可以有多个值,所以我的代码失败了。

{
    "id": 4674388066436,}
wellen2oo3 回答:用于数组值的数组过滤器

您的基本问题是您有一个多维数组,并且没有在所有级别上进行迭代。为了使这项工作有效,我必须重新设计整个逻辑,但是我确实希望这将是一次很好的学习练习。

array_filter函数仅适用于给定级别。您可以保留它,但我将提出一个仅使用嵌套循环的解决方案:

/**
 * Selects products where options match the searched one by removing the ones that don't match.
 */
function selectProductsWithMatchingOptions(array $products,string $filterName,string $filterValue): array
{
    foreach ($products as $key => $product) {
        if (!hasMatchingOption($product['options'],$filterName,$filterValue)) {
            unset($products[$key]);
        }
    }
    return $products;
}

/**
 * Checks whether the searched filter is within any of the options for the product.
 */
function hasMatchingOption(array $options,string $filterValue): bool
{
    foreach ($options as $option) {
        // this part takes care of "values",which is an array
        if (is_array($option[$filterName]) && valueIsListed($option[$filterName],$filterValue)) {
            return true;
        // this part takes care of "name",which is a string
        } elseif (is_string($option[$filterName]) && stringMatches($filterValue,$option[$filterName])) {
            return true;
        }
    }
    return false;
}

/**
 * Checks if a value is in the list of values.
 */
function valueIsListed(array $values,string $filterValue): bool
{
    // we have to iterate and check with stripos because in_array can't handle case
    foreach ($values as $value) {
        if (stringMatches($filterValue,$value)) {
            return true;
        }
    }
    return false;
}

function stringMatches(string $needle,string $haystack): bool
{
    return stripos($needle,$haystack) !== false;
}

现在,如果您使用阵列对此进行测试:

$filtered = selectProductsWithMatchingOptions($array,'name','mAterial');

$filtered = selectProductsWithMatchingOptions($array,'values','BLUE');

转储$filtered应该显示期望的结果。

我做了几个功能,因为我更喜欢提取较小的逻辑。它使代码更简洁。另一种选择是将布尔值存储在变量中,以知道我们是否找到了匹配项,这往往会降低可读性。另外,通过这种方式,我们可以在找到匹配项后立即返回true,从而更优雅地放弃循环。这比必须进行多个级别的break更好。

请注意,我尚未将'options'键作为参数传递,因为它是唯一可以迭代的键-此函数不适用于'id''title'。可以对其进行修改以解决这些问题,但我将由您自己决定。

还请注意,即使选项的数量发生了更改(您在注释中提到的max为3),该功能仍然可以使用,因为它与元素的数量无关。只要不需要太多努力,就始终寻求更通用的解决方案。待会儿你会谢谢你的。

,

您需要区分数组值或常规值,因为它们需要不同的匹配。

您可以做的一件事是编写一个逻辑,以判断一个值是否是一个数组,然后将其他任何类型的值强制放入只有一个元素的数组中。

$key = 'options';
$attr = 'values';
$search = 'blue';

$expected = array_filter($array,function($el) use ($key,$attr,$search) {
  $values = $el[$key];
  if (is_array($value)) {
    $values = array_column($value,$attr);
  } else {
    $value = array($value);
  }

  foreach ($value as $body) {
    foreach ((array)$body as $contents) {
      if (stripos($contents,$search) !== false) {
        return true;
      }
    }
  }
  return false;
}
本文链接:https://www.f2er.com/2611533.html

大家都在问