抽象一下需求:
在构建某个对象时,它拥有多个属性,每个属性拥有多个可选的值,需要穷举出每个属性不同的选择组合构建出的不同对象,比如:
输入参数:
$arr = [
'Name' => ['Jack', 'Lily', 'Martin'],
'Age' => ['18', '12'],
'Gender' => ['male', 'female'],
'Address' => ['Alexander', 'Huston', 'NewYork'],
];
从每个属性中取一个值,根据排列组合计算知道可以得到 36 个不同的人。
期望结果:
篇幅原因,中间省略掉。
array (
0 =>
array (
'Name' => 'Jack',
'Age' => '18',
'Gender' => 'male',
'Address' => 'Alexander',
),
1 =>
array (
'Name' => 'Jack',
'Age' => '18',
'Gender' => 'male',
'Address' => 'Huston',
),
...
34 =>
array (
'Name' => 'Martin',
'Age' => '12',
'Gender' => 'female',
'Address' => 'Huston',
),
35 =>
array (
'Name' => 'Martin',
'Age' => '12',
'Gender' => 'female',
'Address' => 'NewYork',
),
)
实现代码:
/**
* 排列组合
* @param arr
* @return array
*/
function pac(arr): array
{
if (empty(arr)) {
return [];
}n = count(arr); // 维度数量count = 1; // 结果总数
size = []; // 每个属性的可选值个数visit = []; // 每个属性当前访问到的位置(下标)
keyIndex = []; // 保存每个属性的keyres = []; // 保存结果
// 初始化
i = 0;
foreach (arr as key =>values) {
size[i] = count(values);visit[i] = 0;count *= count(values);keyIndex[i] =key;
i ++;
}m = 0;
temp = [];
while (true) {
for (i = 0; i<n; i++ ) {
// 取当前位置的下一个位置记录到最终的数组中temp[m][i] = visit[i] + 1;
}
m ++;
for (i = n - 1;i >= 0; i-- ) {
// 取的是可选值的最后一个值时,重置位置记录,下一个组合从0位置开始
if (visit[i] ==size[i] - 1) {visit[i] = 0;
} else {
// 当前属性未取完
break;
}
}
// 当所有属性的值都取完了,经过最后一次i--, i 值变为 -1,循环完成
if (i < 0) {
break;
}
// 位置后移
visit[i] ++;
}
for (i = 0;i < count;i ++) {
for (j = 0;j < n;j ++) {
res[i][keyIndex[j]] = arr[keyIndex[j]][temp[i][j]-1];
}
}
return $res;
}
如果需求是想要从多个元素中取n个出来,得到多种不同的结果,如果可选元素集合为['a', 'b','c']
,n为2,这样传值:
$arr = [
['a', 'b','c'],
['a', 'b','c'],
];
得到的结果(部分):
array (
0 =>
array (
0 => 'a',
1 => 'a',
),
1 =>
array (
0 => 'a',
1 => 'b',
),
...
7 =>
array (
0 => 'c',
1 => 'b',
),
8 =>
array (
0 => 'c',
1 => 'c',
),
)
PHP数组多属性进行排列组合
原文链接:https://beltxman.com/3770.html,若无特殊说明本站内容为 行星带 原创,未经同意禁止转载。