0

Is there a more declarative / less horrible way of writing this (deliberately simplified) code?

I realise I can use ->each(), but that still doesn't get rid of the nesting in this case?

Note I do need to generate all the combinations, and I have a mixture of things to loop through - configuration data, ordinary arrays, Eloquent, though obviously I could convert them first...

    foreach(config('app.goals') as $goal) {

      foreach(config('app.age_groups') as $ages) {

        foreach($regions as $region_name => $region_id) {

          foreach($interests->pluck('name')->prepend('') as $interest) {

            foreach(config('app.devices') as $device) {

              $record = new Foo();
              $record->goal = $goal;
              $record->age  = $age;
              $record->region = $region_id;
              $record->interest = $interest;
              $record->device = $device;

              $record->save();

            }
          }
        }
      }
    }

Unclear if there's a Collection method that can help? e.g.

holygrail(config('app.goals'),config('app.age_groups'),$regions...)->each(function($combination) {
    // logic for every combination
});
William Turrell
  • 3,227
  • 7
  • 39
  • 57
  • The way you did it currently, each `$record` item will just keep the last iterated value, I guess that's not what you want? – Kévin Bibollet May 13 '19 at 11:36
  • What are the `$regions` and `$interests`? Don't worry about trying to simplify your code too much as in quite a few cases it can actually work out being harder to give an actual answer that can help. – Rwd May 13 '19 at 11:42
  • @KévinBibollet the existing code *does* work - it generates every combination of model, but I wondered if there was a command that could remove the nesting - e.g. specify them all in a single line `something(config(app.goals),config('app.age_groups'),$regions,$interests)->each(...` and still have it iterate? – William Turrell May 13 '19 at 11:50
  • 1
    As far as I know, I don't think so... – Kévin Bibollet May 13 '19 at 11:54
  • @RossWilson yep sorry… the app generates combinations of requests to run through an API (Facebook, in this instance) so $regions is actually a couple of arrays from app/config.php, which have been converted to collections and merge, and the other is the result of `Interest::get()` on a model. I'm sure I could get everything into a collection, if that helps. I just want to find a way to make the code more "flat" - if you see what I mean - as I will need to keep adding further parameters. – William Turrell May 13 '19 at 11:56
  • 1
    @William, I think you can push all the records in an array and then do a bulk insertion by using `Foo::insert()` or whatever method you choose, outside the loop. This will decrease your insertion time a lot in a more sophisticated way. – Shudhansh Shekhar May 13 '19 at 11:58
  • Possible duplicate of [How to generate in PHP all combinations of items in multiple arrays](https://stackoverflow.com/questions/8567082/how-to-generate-in-php-all-combinations-of-items-in-multiple-arrays) – Fitzi May 13 '19 at 13:08

1 Answers1

0

crossJoin() seems to do what I need, it creates an array matrix of every combination.

$matrix = collect($goals)->crossJoin(
            $ages,
            $regions,
            $interests,
            $devices
);

So you have an array full of elements, each of them a permutation, e.g:

array(5) {
  [0]=>
  string(5) "REACH"
  [1]=>
  string(5) "18-65"
  [2]=>
  string(9) "Worldwide"
  [3]=>
  string(11) "Programming"
  [4]=>
  string(7) "desktop"
}

The Laravel source is in: \Illuminate\Support\Arr::crossJoin

William Turrell
  • 3,227
  • 7
  • 39
  • 57