如何使用可选项生成多个数组的所有唯一组合?


How can I generate all unique combinations of multiple array's with optionals?

我想将多个数组中的所有值组合起来以创建唯一的组合。这里有一个问题:有些数组可以是可选的。

例如:我正在配置一台个人电脑,我有两个选择:

  • 5种机箱(包括风扇、电源、主板)
  • 5种磁盘类型(可选)
  • 5种内存(可选)
  • 5种显卡(可选)

正如你所看到的,结果可以是任何组合:

  1. 机箱类型1,磁盘类型3,内存类型5,显卡类型1
  2. 机箱类型1,磁盘类型3,内存类型5,显卡类型2
  3. 机箱类型1,磁盘类型3,内存类型5,显卡类型3
  4. 机箱类型1,无磁盘,内存类型5,显卡类型2
  5. 机箱类型1,无磁盘,内存类型5,无显卡
  6. 机箱类型1,无磁盘,无内存,无显卡
  7. 等。

要确定一系列产品是否是可选的,'optional' => [0|1]部分已包含在数组中:-)

下面的数组是从'生产'中使用的数组中提取出来的,这些数组应该被组合在一起:

array(
    array('optional' => 0, 0, 1),
    array('optional' => 0, 3, 4),
    array('optional' => 0, 6, 7, 8),
    array('optional' => 1, 6, 7, 8, 2),
    array('optional' => 1, 6, 7, 8, 5, 9),
    array('optional' => 1, 6, 7, 8, 10, 11, 12)
)

输出应该是这样的:

0, 3, 6
0, 3, 7
0, 3, 8
0, 4, 6
0, 4, 7
0, 4, 8
1, 3, 6
1, 3, 7
1, 3, 8
[...]
0, 3, 6, 2  <-- outcome with an optional product from the 4th array
0, 3, 7, 9  <-- outcome with an optional product from the 5th array
0, 3, 8, 12 <-- outcome with an optional product from the 6th array

正如你所看到的,上面的数组被组合成一个数组。有些子数组是强制性的,其中optional = 0,或optional = 1。

在可选数组出现之前,我使用了以下函数:

<?PHP
function generateCombinations(array $array) {
    foreach (array_pop($array) as $value) {
        if (count($array)) {
            foreach (generateCombinations($array) as $combination) {
                yield array_merge([$value], $combination);
            };
        } else {
            yield [$value];
        }
    }
}
?>

通过:

foreach ( generateCombinations($ArrCombinateMe) as $combination ){
    // Some code here
}

该函数工作完美,所以我想使用类似的东西,准确地说,我不想失去生成器函数,因为它真的是内存友好的(我以前的函数将在返回可用输出之前组合所有内容,它只能在4GB内存中返回320万个组合。这个函数在测试期间已经通过了320万次(千倍)。

目前我想还包括可选数组的,以便这些也被生成:-)

请注意:我喜欢速度,但对于这个函数来说,这并不重要,因为它将作为后台作业运行,没有任何用户交互。

我希望有人能帮助我:-)

答案似乎比理解问题要简单得多。您不需要更改过程-只需在可选数组中包含'null'作为可能的值。

这种方式将返回null值的数组,但它们的索引将表示源。以以下数组为例:

$data = array(
    'Chassis'   => array(0, 1, 2),
    'Mainboard' => array(3, 4, 5),
    'PSU'       => array(6, 7, 8),
    'Disk'      => array(null, 9, 10),
    'GFX'       => array(null, 11, 12),
    'Memory'    => array(null, 13, 14, 15)
);

其中一个结果将是:[0,3,6,null,11,null] *,这意味着GFX被包括在内。

如果你不想要

的空值,你可以过滤结果
array_filter($combination, 'is_int')

'is_int'参数仅用于正确处理0。如果0不是有效的id,那么您可以跳过它(并且可以使用0而不是null)

*)实际上最后一个元素跳到第一个位置,因为array_merge() args顺序

编辑:

这个生成器本身快了35%(内存使用相同),并且不需要过滤,总体速度是原来的两倍:

function generateCombinations(array $array) {
    foreach (array_pop($array) as $id) {
        if (empty($array)) {
            yield isset($id) ? [$id] : [];
            continue;
        }
        foreach (generateCombinations($array) as $combination) {
            if (isset($id)) { $combination[] = $id; }
            yield $combination;
        }
    }
}