1

I have a multidimensional array:

$items = array(
   array("A1", "A2", "A3"),
   array("B1","B2","B3","B4"),
   array("C1","C2","C3","C4","C5"),
   array("D1","D2","D3")); 

I need to build a list of unique strings, and each should contain one item from each array, like this:

A1 B1 C1 D1,
A1 B1 C1 D2,
A1 B1 C1 D3,
A1 B1 C2 D1,
A1 B1 C2 D2,
etc...

Example data above should produce 180 combinations (3*4*5*3=180).

The difficulty is that the code (in best case) should work for any number of arrays. Not just for 4 as in the example above.

For example, I would add: array("E1", "E2"); and code should still work.

A simpler version might be working with fixed set of arrays, for example 4 (as in the example above).

Of course I can use for loops, but in this case it will be required to add another for loop, each time I add another array of data (not so universal, right?).

Here's what I tried, but it didn't work out:

$items = array(
   array("A1", "A2", "A3"),
   array("B1","B2","B3","B4"),
   array("C1","C2","C3","C4","C5"),
   array("D1","D2","D3"));

$depth = count($items);
$index = $depth - 1;

for ($i = 0; $i <= $index; $i++) {
   $depth2 = count($items[$i]);
   $index2 = $depth2 - 1;
   echo "SET: ";
   for ($i2 = 0; $i2 <= $index2; $i2++) {
      echo $items[$i2][$i].", ";
   }
   echo "<br>";
}

Expected result is the list of 180 unique strings, like:

A1 B1 C1 D1,
A1 B1 C1 D2,
A1 B1 C1 D3,
A1 B1 C2 D1,
A1 B1 C2 D2,
etc...

1 Answer 1

2

You can use recursion to build the result set similar to the way you might permute an array with backtracking. The idea is to include each item one at a time from each array and add it to the in-progress result, then recurse on that possibility. After exploring all of the result possibilities for a given element, we discard it from further consideration and move on to the next element, repeating the process.

<?php

function combos($items, &$curr=[], &$res=[], $i=0) {
    if ($i >= count($items)) {
        $res[]= $curr;
    }
    else {
        foreach ($items[$i] as $e) {
            $curr[]= $e;
            combos($items, $curr, $res, $i + 1);
            array_pop($curr);
        }
    }

    return $res;
}

$items = [
    ["A1", "A2", "A3"],
    ["B1","B2","B3","B4"],
    ["C1","C2","C3","C4","C5"],
    ["D1","D2","D3"]
];
$i = 0;

foreach (combos($items) as $combo) {
    echo str_pad($i++ . ": ", 5, " ", false) . implode(" ", $combo) . "\n";
}

Output:

  0: A1 B1 C1 D1
  1: A1 B1 C1 D2
  2: A1 B1 C1 D3
  3: A1 B1 C2 D1
  4: A1 B1 C2 D2
  5: A1 B1 C2 D3
  6: A1 B1 C3 D1
  7: A1 B1 C3 D2
...
172: A3 B4 C3 D2
173: A3 B4 C3 D3
174: A3 B4 C4 D1
175: A3 B4 C4 D2
176: A3 B4 C4 D3
177: A3 B4 C5 D1
178: A3 B4 C5 D2
179: A3 B4 C5 D3
Sign up to request clarification or add additional context in comments.

2 Comments

Amazing! Work like a charm! Thank you ggorlen! Great and easy to understand solution! (should i mark this question as solved, or something?)
Glad it worked out. Since you posted the Q, you decide when and if it's solved (but it's a good idea to eventually pick a solution)!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.