seblavoie
6/2/2016 - 10:12 PM

Get all combinations of two collections

Get all combinations of two collections

<?php

/**
 * If you have two sets of collections, which you would previously have used a nested foreach to do something to each unique
 * combination of items, you can use this macro to get it done instead!
 * 
 * It will return a collection of tuples that represent the combination of the two collections. If you'd like to add keys to the tuple
 * you can pass that in as an optional second argument!
 */

Collection::macro('combinations', function($combineWith, $keys = [0, 1]) {
    return $this->reduce(function ($combinations, $originalItem) use ($combineWith, $keys) {
        return $combinations->push($combineWith->map(function ($otherItem) use ($originalItem, $keys) {
            return [ $keys[0] => $originalItem, $keys[1] => $otherItem ];
        }));
    }, new static)
        ->flatten(1);
});

$result = collect([ "a", "b" ])
            ->combinations(collect([ 1, 2, 3 ]), [ 'letter', 'number' ]);

$this->assertEquals([
    ["letter" => "a", "number" => 1],
    ["letter" => "a", "number" => 2],
    ["letter" => "a", "number" => 3],
    ["letter" => "b", "number" => 1],
    ["letter" => "b", "number" => 2],
    ["letter" => "b", "number" => 3]
  ], $result->all());