I tried another approach but eventually ended with something similar to Valentin CLEMENT's solution although my function is more verbose.
Still, the originality is that this function gets you a tree of combinations, which may (or may not) be usefull depending on what you intend to do.
Here is the code :
function getCombinations( $arrayList, $index = 0 )
{
$subCombinations = $combinations = '';
if ( $index < count( $arrayList )-1 )
{
$subCombinations = getCombinations( $arrayList, $index+1 );
}
foreach( $arrayList[$index] as $item )
{
$combinations[$item] = $subCombinations ;
}
return $combinations;
}
$combinations = getCombinations( $array );
print_r( $combinations );
With example data :
$array = array(
array('a', 'b', 'c'),
array('e', 'f', 'g'),
array('h', 'i', 'j', 'k', 'l')
);
It will output :
Array
(
[a] => Array
(
[e] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
[f] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
[g] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
)
[b] => Array
(
[e] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
[f] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
[g] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
)
[c] => Array
(
[e] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
[f] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
[g] => Array
(
[h] =>
[i] =>
[j] =>
[k] =>
[l] =>
)
)
)
And then it requires additional code to draw expected result :
function drawCombinations( $combinations, $line = array() )
{
foreach( $combinations as $value => $children )
{
array_push( $line, $value );
if ( is_array( $children ) )
{
drawCombinations( $children, $line );
}
else
{
echo implode( " ", $line ) ." \n";
}
array_pop( $line );
}
}
drawCombinations( $combinations );
To produce :
a e h
a e i
a e j
a e k
a e l
a f h
a f i
a f j
a f k
a f l
a g h
a g i
a g j
a g k
a g l
b e h
b e i
b e j
b e k
b e l
b f h
b f i
b f j
b f k
b f l
b g h
b g i
b g j
b g k
b g l
c e h
c e i
c e j
c e k
c e l
c f h
c f i
c f j
c f k
c f l
c g h
c g i
c g j
c g k
c g l
As I said eariler, if you don't need this tree of results (that your questions did not mention, I just produced this while searching the best way), Valentin CLEMENT's approach could be better (if you don't use too large dataset, I will explain why after).
I rewrote it a bit, in a way I think more readable and usable :
function expand( $array, $from = 0, $length = false )
{
if ( $length === false )
{
$length = count( $array );
}
if ( $length == $from )
{
return array('');
}
else
{
$result = array();
foreach( $array[$from] as $x )
{
foreach( expand( $array, $from+1, $length ) as $tail )
{
$result[] = trim("$x $tail");
}
}
return $result;
}
}
$combinations = expand( $array );
print_r( $combinations );
It returns the following array :
Array
(
[0] => a e h
[1] => a e i
[2] => a e j
[3] => a e k
[4] => a e l
[5] => a f h
[6] => a f i
[7] => a f j
[8] => a f k
[9] => a f l
[10] => a g h
[11] => a g i
[12] => a g j
[13] => a g k
[14] => a g l
[15] => b e h
[16] => b e i
[17] => b e j
[18] => b e k
[19] => b e l
[20] => b f h
[21] => b f i
[22] => b f j
[23] => b f k
[24] => b f l
[25] => b g h
[26] => b g i
[27] => b g j
[28] => b g k
[29] => b g l
[30] => c e h
[31] => c e i
[32] => c e j
[33] => c e k
[34] => c e l
[35] => c f h
[36] => c f i
[37] => c f j
[38] => c f k
[39] => c f l
[40] => c g h
[41] => c g i
[42] => c g j
[43] => c g k
[44] => c g l
)
And it is then easy to achieve expected result :
echo implode( "\n", $combinations )."\n";
Will output :
a e h
a e i
a e j
a e k
a e l
a f h
a f i
a f j
a f k
a f l
a g h
a g i
a g j
a g k
a g l
b e h
b e i
b e j
b e k
b e l
b f h
b f i
b f j
b f k
b f l
b g h
b g i
b g j
b g k
b g l
c e h
c e i
c e j
c e k
c e l
c f h
c f i
c f j
c f k
c f l
c g h
c g i
c g j
c g k
c g l
I thought, at first, that my solution was cosuming more memory than Valentin's one because it uses arrays, but when I tested it out, I realized that it indeed it uses slightly less memory.
Displaying the memory metrics against the two methods gave those results :
drawCombinations( getCombinations( $array ));
echo memory_get_usage()." ". memory_get_peak_usage()."\n";
// 238736 244896
echo implode( "\n", expand( $array ) )."\n";
echo memory_get_usage()." ". memory_get_peak_usage()."\n";
// 238912 252304
But it gets more important when using bigger input values, with :
$array = array(
array('a', 'b', 'c'),
array('e', 'f', 'g'),
array('h', 'i', 'j', 'k', 'l'),
array('m', 'n', 'o', 'p', 'q', 'r', 's'),
array('t', 'u', 'v', 'x', 'y', 'z')
);
getCombinations gives :
drawCombinations( getCombinations( $array ));
echo memory_get_usage()." ". memory_get_peak_usage()."\n";
// 242376 253008
expand gives :
echo implode( "\n", expand( $array ) )."\n";
echo memory_get_usage()." ". memory_get_peak_usage()."\n";
//242544 704520
The reason is obvious if we look at the array produced by each function, since the first solution stores less duplicate values (I am not sure how PHP handles the duplicates arrays ending each branch of the tree).
Once again, depending on what you plain to achieve, you will care or not.
"Echoing" each rows on the fly instead of creating a big result array decreases slightly the memory peak issue but expand() remains more memory consuming as dataset grows.
I hope it helps, at least that was interesting to me ;)