这是我的第一个问题:)
我有一个包含多个数组子节点的数组,每个子节点都有唯一的值,并希望获得这些值的所有可能的唯一组合。
数组的数量是已知的,但可能会随着时间而改变。
例如,
array(
[0] => array([0]=>'blue',[1]=>'red'),
[1] => array([0]=>'sunny',[1]=>'cloudy'),
[2] => array([0]=>'sweet',[1]=>'acid');
我该怎么办才能获得:
array(
[0] => array([0]=>'blue',[1]=>'sunny',[2]=>'sweet'),
[1] => array([0]=>'blue',[1]=>'sunny',[2]=>'acid'),
[2] => array([0]=>'blue',[1]=>'cloudy',[2]=>'sweet'),
[3] => array([0]=>'blue',[1]=>'cloudy',[2]=>'acid'),
[4] => array([0]=>'red',[1]=>'sunny',[2]=>'sweet'),
[5] => array([0]=>'red',[1]=>'sunny',[2]=>'acid'),
[6] => array([0]=>'red',[1]=>'cloudy',[2]=>'sweet'),
[7] => array([0]=>'red',[1]=>'cloudy',[2]=>'acid'));
我尝试过使用嵌套循环,但我的逻辑不太强。
非常感谢,如果有人可以放弃一些光线
答案 0 :(得分:8)
(注意:需要稍微修改才能在PHP中使用< 5.3)
执行此操作(example在线翻译):
$f = function () { return func_get_args(); };
$res = array_outer($f,
array("blue", "red"),
array("sunny", "cloudy"),
array("sweet", "acid"));
在Mathematica的Outer
中受到启发的函数array_outer
就是:
/**
* A generalization of the outer product, forming all the possible
* combinations of the elements of any number of arrays and feeding
* them to $f.
* The keys are disregarded
**/
function array_outer($f, array $array1) {
$res = array();
$arrays = func_get_args();
array_shift($arrays);
foreach ($arrays as $a) {
if (empty($a))
return $res;
}
$num_arrays = count($arrays);
$pos = array_fill(0, $num_arrays, 0);
while (true) {
$cur = array();
for ($i = 0; $i < $num_arrays; $i++) {
$cur[] = $arrays[$i][$pos[$i]];
}
$res[] = call_user_func_array($f, $cur);
for ($i = $num_arrays-1; $i >= 0; $i--) {
if ($pos[$i] < count($arrays[$i]) - 1) {
$pos[$i]++;
break;
} else {
if ($i == 0)
break 2;
$pos[$i] = 0;
}
}
}
return $res;
}
答案 1 :(得分:4)
这是一种递归方法:
$arr = array(
0 => array(0 =>'blue', 1 =>'red'),
1 => array(0 =>'sunny', 1 =>'cloudy'),
2 => array(0 =>'sweet', 1 =>'acid')
);
$combinations = array();
getArrayCombinations($arr, $combinations);
echo '<pre>';print_r($combinations);
/**
* Creates an array with all possible combinations
* @param array main_array - Array to find all the possible combinations of
* @param array combinations - Array to store the resulting array in
* @param array batch
* @param int index
*/
function getArrayCombinations($main_array, &$combinations, $batch=array(), $index=0)
{
if ($index >= count($main_array))
array_push($combinations, $batch);
else
foreach ($main_array[$index] as $element)
{
$temp_array = $batch; array_push($temp_array, $element);
getArrayCombinations($main_array, $combinations, $temp_array, $index+1);
}
}
答案 2 :(得分:2)
你真正想要的是一种迭代序列的方法:
000
001
010
011
100
101
110
111
如果我们不必假设每个输入数组的大小相同,那也会很好。因此,如果我们将第二个数组的大小减小1:
array(
[0] => array([0]=>'blue',[1]=>'red'),
[1] => array([0]=>'sunny'),
[2] => array([0]=>'sweet',[1]=>'acid');
...我们希望该列的最大值减少1:
000
001
100
101
这种抽象使问题更容易思考。你会如何重复这个序列?在每次迭代时,将最右边的列增加1.如果这样做会将其增加到超出其最大值,则将其重置为0并向左移动一列。现在,您重复刚才在最后一栏中所做的事情。如果您也无法增加此列,请将其重置为0,向左移动,冲洗并重复。如果你一直移动并且在没有超出其最大值的情况下无法增加任何列,那么你就完成了。
我们可以在PHP迭代器中包含上述逻辑:
class Sequence implements Iterator {
private $input;
private $hasNext;
private $positions;
public function __construct(array $input) {
$this->input = $input;
}
public function rewind() {
$this->hasNext = true;
$this->positions = array();
for ($i = 0; $i < count($this->input); $i++) {
$this->positions[$i] = 0;
}
}
public function valid() {
return $this->hasNext;
}
public function current() {
$current = array();
for ($i = 0; $i < count($this->positions); $i++) {
$current[] = $this->input[$i][$this->positions[$i]];
}
return $current;
}
public function key() {}
public function next() {
for ($i = count($this->positions) - 1; $i >= 0; $i--) {
if ($this->positions[$i] < count($this->input[$i]) - 1) {
$this->positions[$i]++;
break;
} else {
$this->positions[$i] = 0;
$this->hasNext = $i !== 0;
}
}
}
}
next()
是上述逻辑的实现。 reset()
只需将每列设置回0,current()
使用当前序列作为输入的索引,以返回当前值。
此处处于行动状态(删除“阴天”以显示解决方案的一般性):
$input = array(
array('blue', 'red'),
array('sunny'),
array('sweet', 'acid')
);
$lst = new Sequence($input);
foreach ($lst as $elt) {
print(implode(', ', $elt) . "\n");
}
及其输出:
blue, sunny, sweet
blue, sunny, acid
red, sunny, sweet
red, sunny, acid
答案 3 :(得分:2)
非常简单的解决方案:
$arr = array(
array('a', 'b', 'c'),
array('x', 'y', 'z'),
array('1', '2')
);
$result = array();
foreach ($arr as $a) {
if (empty($result)) {
$result = $a;
continue;
}
$res = array();
foreach ($result as $r) {
foreach ($a as $v) {
$res[] = array_merge((array)$r, (array)$v);
}
}
$result = $res;
}
var_dump($result);
答案 4 :(得分:0)
latenight伪代码:
result = []
counter = 0
for i in length(array[0]):
for j in length(array[1]):
for k in length(array[2]):
result[counter] = aray(0: array[0][i], 1: array[1][j], 2: array[2][k])
counter+=1
虽然如果数组的数量会变大或动态变化,可能会对递归方法提出强烈的要求