什么是笛卡尔积
笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X×Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。
例如:
假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为:
{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}.
在PHP中的实现
基础实现
public function singleDescartes(array $list): array{
$a = array_shift($list);
!is_array($a) && ($a = [$a]);
$a = array_chunk($a, 1);
do{
$result = [];
$b = array_shift($list);
!is_array($b) && ($b = [$b]);
foreach ($a as $p) {
foreach (array_chunk($b, 1) as $q) {
$result[] = array_merge($p, $q);
}
}
$a = $result;
}while(!empty($list));
return $result;
}
$list = [
['黑色','红色'],
['标准','加棉'],
['37码','38码','39码'],
];
$re = singleDescartes($list);
print_r(json_encode($re, JSON_UNESCAPED_UNICODE));
// output
[
["黑色", "标准", "37码"],
["黑色", "标准", "38码"],
["黑色", "标准", "39码"],
["黑色", "加棉", "37码"],
["黑色", "加棉", "38码"],
["黑色", "加棉", "39码"],
["红色", "标准", "37码"],
["红色", "标准", "38码"],
["红色", "标准", "39码"],
["红色", "加棉", "37码"],
["红色", "加棉", "38码"],
["红色", "加棉", "39码"]
]
扩展到项目
public function descartes(array $attrWithOptions): array{
$a = array_shift($attrWithOptions);
$a['options'] = array_chunk($a['options'], 1);
do{
$b = array_shift($attrWithOptions);
$r = [
'attrName' => "{$a['attrName']}+{$b['attrName']}",
'options' => []
];
foreach ($a['options'] as $option1) {
foreach (array_chunk($b['options'], 1) as $option2) {
$r['options'][] = array_merge($option1, $option2);
}
}
$a = $r;
} while (count($attrWithOptions) > 0);
return $r;
}
$list = [
[
'attrId' => 1,
'attrName' => '容量',
'options' => [
['id' => 34, 'title' => '64G'],
['id' => 35, 'title' => '128G']
]
],
[
'attrId' => 2,
'attrName' => '颜色',
'options' => [
['id' => 43, 'title' => '玫瑰金'],
['id' => 44, 'title' => '银色'],
['id' => 45, 'title' => '黑色']
]
],
[
'attrId' => 3,
'attrName' => '网络',
'options' => [
['id' => 53, 'title' => '联通'],
['id' => 54, 'title' => '移动'],
['id' => 55, 'title' => '电信']
]
]
];
$re = descartes($list);
print_r(json_encode($re, JSON_UNESCAPED_UNICODE));
// output
{
"attrName": "容量+颜色+网络",
"options": [
[
{"id": 34, "title": "64G"}, {"id": 43, "title": "玫瑰金"}, {"id": 53, "title": "联通"}],
[{"id": 34, "title": "64G"}, {"id": 43, "title": "玫瑰金"}, {"id": 54, "title": "移动"}],
[{"id": 34, "title": "64G"}, {"id": 43, "title": "玫瑰金"}, {"id": 55, "title": "电信"}],
[{"id": 34, "title": "64G"}, {"id": 44, "title": "银色"}, {"id": 53, "title": "联通"}],
[{"id": 34, "title": "64G"}, {"id": 44, "title": "银色"}, {"id": 54, "title": "移动"}],
[{"id": 34, "title": "64G"}, {"id": 44, "title": "银色"}, {"id": 55, "title": "电信"}],
[{"id": 34, "title": "64G"}, {"id": 45, "title": "黑色"}, {"id": 53, "title": "联通"}],
[{"id": 34, "title": "64G"}, {"id": 45, "title": "黑色"}, {"id": 54, "title": "移动"}],
[{"id": 34, "title": "64G"}, {"id": 45, "title": "黑色"}, {"id": 55, "title": "电信"}],
[{"id": 35, "title": "128G"}, {"id": 43, "title": "玫瑰金"}, {"id": 53, "title": "联通"}],
[{"id": 35, "title": "128G"}, {"id": 43, "title": "玫瑰金"}, {"id": 54, "title": "移动"}],
[{"id": 35, "title": "128G"}, {"id": 43, "title": "玫瑰金"}, {"id": 55, "title": "电信"}],
[{"id": 35, "title": "128G"}, {"id": 44, "title": "银色"}, {"id": 53, "title": "联通"}],
[{"id": 35, "title": "128G"}, {"id": 44, "title": "银色"}, {"id": 54, "title": "移动"}],
[{"id": 35, "title": "128G"}, {"id": 44, "title": "银色"}, {"id": 55, "title": "电信"}],
[{"id": 35, "title": "128G"}, {"id": 45, "title": "黑色"}, {"id": 53, "title": "联通"}],
[{"id": 35, "title": "128G"}, {"id": 45, "title": "黑色"}, {"id": 54, "title": "移动"}],
[{"id": 35, "title": "128G"}, {"id": 45, "title": "黑色"}, {"id": 55, "title": "电信"}]
]
}