如何在 PHP 中生成多个数组中所有可能的项目选择以缓存过滤系统

How to generate in PHP all possible selections of items in multiple arrays to cache a filter system

我创建了一个过滤系统,您可以过滤多个分类的结果。

例如: 显示游戏和生产力类别中所有带有硬件标签的新闻文章和视频,您可以这样选择

Content Type
[x] news article
[x] video
[ ] opinion

Category
[x] gaming
[x] productivity
[ ] music

Tags
[x] hardware
[ ] software

这可以用这样的数组表示:

[ [ 'news article', 'video' ], [ 'gaming', 'productivity' ], [ 'hardware' ] ];

现在基本上我想要的是得到一个包含所有可能组合的数组。所以它会像这样开始:

[
  [ [], [], [], ], // no selections
  [ ['news article'], [], [], ], // only news article selected
  [ ['video'], [], [], ],
  [ ['opinion'], [], [], ],
  [ ['news article, video'], [], [], ],
  [ ['news article, opinion'], [], [], ],
  [ ['video, opinion'], [], [], ],
  [ ['news article'], ['gaming'], [], ],
  ...
  [ ['news article', 'video', 'opinion'], ['gaming', 'productivity', 'music'], ['hardware','software'], ],
];

这似乎是一个很常见的问题,但到目前为止我发现的唯一组合算法是仅与每个数组中的一个元素进行组合的算法。我意识到我想要创建的组合集会变得非常大,速度非常快,但是有没有一种已知的方法或 PHP 函数可以用来生成这样的数组?

首先,使用以下函数生成所有可能的选择:

function array_combine_values($array)
{
    $len = count($array);
    $result = [];
    for($i = 0; $i < pow(2, $len); $i++) {
        $row = [];
        $indexes = str_split(str_pad(decbin($i), $len, '0', STR_PAD_LEFT));
        foreach($indexes as $key => $index) {
            if ($index) $row[] = $array[$key];
        }
        $result[] = $row;
    }
    return $result;
}

示例:

print_r(array_combine_values(['a', 'b']));

输出:

Array
(
    [0] => Array
        (
        )
    [1] => Array
        (
            [0] => b
        )
    [2] => Array
        (
            [0] => a
        )
    [3] => Array
        (
            [0] => a
            [1] => b
        )
)

二、数组笛卡尔积的函数:

function array_cartesian_product($array)
{
    if (empty($array)) return [[]];

    $column = array_shift($array);
    $cartesian = array_cartesian_product($array);

    $result = [];
    foreach ($column as $row) {
        foreach ($cartesian as $item) {
            array_unshift($item, $row);
            $result[] = $item;
        }
    }
    return $result;        
}

示例:

print_r(array_cartesian_product([['a', 'b'], ['c', 'd']]));

输出:

Array
(
    [0] => Array
        (
            [0] => a
            [1] => c
        )
    [1] => Array
        (
            [0] => a
            [1] => d
        )
    [2] => Array
        (
            [0] => b
            [1] => c
        )
    [3] => Array
        (
            [0] => b
            [1] => d
        )
)

您的情况下的用法:

$selections = array( 
    ['news article', 'video', 'opinion'], 
    ['gaming', 'productivity', 'music'], 
    ['hardware','software']
);

$result = [];

foreach($selections as $items) {
    $result[] = array_combine_values($items);
}

$result = array_cartesian_product($result);

print_r($result);