Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This is one of those cases where self-generated code and brute force will beat most algorithms on simplicity and performance. In previous answers I've seen lots of recursion, array manipulation and computations, when in actuality what you'd want to do is:</p> <pre><code>foreach ($array[0] as $k0 =&gt; $v0) { foreach ($array[1] as $k1 =&gt; $v1) { if ($k1 == $k0) { continue; } foreach ($array[2] as $k2 =&gt; $v2) { if ($k2 == $k1 || $k2 == $k0) { continue; } $result[] = $v0.$v1.$v2; } } } </code></pre> <p>Of course, you cannot write this unless you know how many arrays are in <code>$array</code>. That's where generated code comes handy:</p> <pre><code>$array = array( array('1', '2'), array('a', 'b', 'c'), array('x', 'y') ); $result = array(); $php = ''; foreach ($array as $i =&gt; $arr) { $php .= 'foreach ($array[' . $i . '] as $k' . $i . ' =&gt; $v' . $i . '){'; if ($i &gt; 0) { $sep = 'if ('; $j = $i - 1; do { $php .= $sep . '$k' . $i . ' == $k' . $j; $sep = ' || '; } while (--$j &gt;= 0); $php .= ') { continue; } '; } } $php .= '$result[] = $v' . implode('.$v', array_keys($array)) . ';' . str_repeat('}', count($array)); eval($php); print_r($result); </code></pre> <p>Note that this routine assumes that <code>$array</code> is a zero-based numerically indexed array, as in your example. It will generate the code quoted above, adjusted for an arbitrary number of arrays.</p> <hr> <h2>Update</h2> <p>Here's an alternative algorithm. It's still self-generated, but less bruteforce. We still have nested loops, except that each loop works on a copy of the array where keys that are currently used by outer loops have been removed from this loop's array. For example, if the values should be (a,b,c) but the outer loops are using the indices 0 and 2, we remove "a" (index 0) and "c" (index 2) and all we have left is "b". It means that loops work only on possible combinations and we don't need a <code>if</code> condition anymore. </p> <p>Furthermore, and this part can be applied to the previous algorithm as well, we process the arrays of values in order from the smallest to the largest so that we guarantee that used indices exist in current array. The downside is it doesn't generate the combinations in the same order. It generates the same combinations, just not in the same order. The code looks like this:</p> <pre><code>$a0 = $array[0]; foreach ($a0 as $k0 =&gt; $v0) { $a2 = $array[2]; unset($a2[$k0]); foreach ($a2 as $k2 =&gt; $v2) { $a1 = $array[1]; unset($a1[$k0], $a1[$k2]); foreach ($a1 as $k1 =&gt; $v1) { $result[] = "$v0$v1$v2"; } } } </code></pre> <p>The above routine sets up a copy of the values at the beginning of every loop, then removes values that are used by outer loops. You can improve this process by setting up a copy of the values <em>only once</em> at the beginning, remove the keys as they are used (at the beginning of each loop) and put them back as they are freed (at the end of each loop). The routine then looks like this:</p> <pre><code>list($a0,$a1,$a2) = $array; foreach ($a0 as $k0 =&gt; $v0) { unset($a1[$k0], $a2[$k0]); foreach ($a2 as $k2 =&gt; $v2) { unset($a1[$k2]); foreach ($a1 as $k1 =&gt; $v1) { $result[] = "$v0$v1$v2"; } $a1[$k2] = $array[1][$k2]; } $a1[$k0] = $array[1][$k0]; $a2[$k0] = $array[2][$k0]; } </code></pre> <p>The actual code that generates the source above is:</p> <pre><code>$keys = array_map('count', $array); arsort($keys); $inner_keys = array(); foreach ($keys as $k =&gt; $cnt) { $keys[$k] = $inner_keys; $inner_keys[] = $k; } $result = array(); $php = 'list($a' . implode(',$a', array_keys($array)) . ')=$array;'; foreach (array_reverse($keys, true) as $i =&gt; $inner_keys) { $php .= 'foreach ($a' . $i . ' as $k' . $i . ' =&gt; $v' . $i . '){'; if ($inner_keys) { $php .= 'unset($a' . implode('[$k' . $i . '],$a', $inner_keys) . '[$k' . $i . ']);'; } } $php .= '$result[] = "$v' . implode('$v', array_keys($array)) . '";'; foreach ($keys as $i =&gt; $inner_keys) { foreach ($inner_keys as $j) { $php .= '$a' . $j . '[$k' . $i . ']=$array[' . $j . '][$k' . $i . "];\n"; } $php .= '}'; } eval($php); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload