如何用PHP生成多数组指定元素数量的所有组合?
解决多数组指定数量元素的组合生成问题
你现在遇到的问题是现有代码只能实现每个数组取1个元素的笛卡尔积,但实际需要从每个数组中抽取指定数量的元素,再生成所有可能的组合。我来给你拆解解决方案:
核心思路
要实现需求,需要分两步走:
- 为每个单独的数组,生成所有「抽取指定数量元素」的子组合(比如从arrayA的6个元素中,生成所有3个元素的组合)
- 将这些子组合数组,再做一次笛卡尔积,得到最终的跨数组组合
具体代码实现
下面是完整的PHP代码,包含两个核心函数:
getSingleArrayCombinations:生成单个数组中指定长度的所有组合getCrossArrayCombinations:将多个子组合数组做笛卡尔积,得到最终结果
<?php // 生成单个数组中指定长度的所有组合 function getSingleArrayCombinations($arr, $takeNum) { $result = []; $arrLength = count($arr); // 如果要取的数量大于数组长度,直接返回空 if ($takeNum > $arrLength || $takeNum <= 0) { return $result; } // 递归生成组合 $generate = function($start, $current) use ($arr, $takeNum, &$result, &$generate) { if (count($current) === $takeNum) { $result[] = implode('+', $current); return; } for ($i = $start; $i < count($arr); $i++) { $current[] = $arr[$i]; $generate($i + 1, $current); array_pop($current); } }; $generate(0, []); return $result; } // 生成多组数据的笛卡尔积 function getCrossArrayCombinations($options) { $combinations = [[]]; foreach ($options as $group) { $temp = []; foreach ($combinations as $existing) { foreach ($group as $item) { $temp[] = array_merge($existing, [$item]); } } $combinations = $temp; } // 将每个组合转为逗号分隔的字符串(可选,根据你的输出需求调整) return array_map(function($item) { return implode(', ', $item); }, $combinations); } // 测试用例 $arrayA = array('A1','A2','A3','A4','A5','A6'); // 取3个 $arrayB = array('B1','B2','B3','B4','B5'); // 取2个 $arrayC = array('C1','C2'); // 取1个 // 第一步:生成每个数组的指定数量组合 $groupA = getSingleArrayCombinations($arrayA, 3); $groupB = getSingleArrayCombinations($arrayB, 2); $groupC = getSingleArrayCombinations($arrayC, 1); // 第二步:生成跨数组的最终组合 $finalCombinations = getCrossArrayCombinations([$groupA, $groupB, $groupC]); // 输出结果示例(只展示前5个,避免内容过多) print_r(array_slice($finalCombinations, 0, 5)); ?>
代码说明
getSingleArrayCombinations用递归的方式生成单个数组的指定长度组合,并且用+连接元素,完全匹配你想要的格式getCrossArrayCombinations是在你原有笛卡尔积代码的基础上修改,接收的是每个数组的子组合数组,最终将每个组合用,连接成字符串- 测试用例运行后,会输出类似这样的结果:
Array ( [0] => A1+A2+A3, B1+B2, C1 [1] => A1+A2+A3, B1+B2, C2 [2] => A1+A2+A3, B1+B3, C1 [3] => A1+A2+A3, B1+B3, C2 [4] => A1+A2+A3, B1+B4, C1 )
注意事项
- 如果数组元素数量较多,且抽取数量较大,生成的组合数会指数级增长(比如示例中总组合数是C(6,3)C(5,2)C(2,1)=20102=400),要注意性能问题
- 如果不需要将元素用
+连接,只需要修改getSingleArrayCombinations中的implode('+', $current)为直接返回$current即可
内容的提问来源于stack exchange,提问作者Uttam Mitra
相关产品推荐
相关产品推荐

