数组值的数组过滤器

array filter for array values

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

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

你的基本问题是你有一个多维数组并且你没有在所有级别上迭代。为了完成这项工作,我不得不重新设计整个逻辑,但我希望这将是一个很好的学习练习。

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 $filterName, 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'.它也可以修改以处理这些问题,但我会把它留给你。

另请注意,即使选项数量发生变化(您在评论中提到最大值为 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;
}