6

When you need to check/have combinations of array elements, how can you avoid nesting foreach?

Example code:

$as = array($optionA1, $optionA2)
$bs = array($optionB1, $optionB2)
$cs = array($optionC1, $optionC2)

foreach ($as as $a) {
    foreach ($bs as $b) {
      foreach ($cs as $c) {
          $result = $this->method($a, $b, $c);
          if ($result) etc
      }
    }
}

Anyone with alternative approaches that can avoid nesting?

koen
  • 13,349
  • 10
  • 46
  • 51
  • Why do you want to avoid nesting? What you have is already the most intuitive solution for most problems. – JSBձոգչ Jul 23 '09 at 18:29
  • 1
    To clarify: I would like to avoid the nesting because it frequently seems to become really difficult to display well coded or clean. I know that's not a reason to give it up, but if there's a neater/slicker alternative I would like to hear of it. – koen Jul 23 '09 at 18:41
  • 1
    You could use recursion instead of iteration. This will move the nesting from your code into the object model. (It's hard to be more specific since your example is so contrived.) – bzlm Feb 16 '10 at 13:22

4 Answers4

7

You could write your own Iterator class which implements the Iterator interface. You could then have its constructor accept the three arrays and then you can use it to loop over every combination with foreach.

However I think this would be significantly slower, so I would avoid it. It would be interesting to know the reasons you want to avoid the nested foreach loops?

Tom Haigh
  • 57,217
  • 21
  • 114
  • 142
  • It would be nice if whoever down-voted me would add a comment – Tom Haigh Feb 16 '10 at 14:52
  • Tom I haven't down voted you but I how to use this iterator interface? if you give me a small algorithm it will be useful! thanks! – Neocortex Mar 04 '14 at 14:33
  • @BannedfromSO Not really sure this was really a good solution - three loops is probably more obvious, so I'm not sure the example is worthwhile – Tom Haigh Mar 04 '14 at 16:26
3

Logically, you have to iterate through each item somehow. You're just shuffling around the process.

If multiple for loops look ugly, maybe you should put your arrays into their own classes, that have their own encapsulated 'checks'.

Rob Elliott
  • 1,998
  • 19
  • 25
1

Have you considered taking the count of each array and multiplying them all together to get a total number of permutations, and then doing a for i to iterate that count? You would have to do some funny counter manipulation for each array, but it should work.

Chris Porter
  • 3,627
  • 25
  • 28
1

You haven't really given enough information to know what the alternative is. If you really want to call method() with all combinations of options from $as, $bs and $cs, then nested loops will do the right thing.

Is it the multiply nested loops that bothers you, or the fact that method() is being called count($as) * count($bs) * count($cs) times?

Ether
  • 53,118
  • 13
  • 86
  • 159