Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

bpolaszek/cartesian-product

Open more actions menu

Repository files navigation

Latest Stable Version License CI Workflow Coverage Total Downloads

Cartesian Product

A simple, low-memory footprint function to generate all combinations from a multi-dimensionnal array.

Usage

use function BenTools\CartesianProduct\combinations;

$data = [
    'hair' => [
        'blond',
        'black'
    ],
    'eyes' => [
        'blue',
        'green',
        function (array $combination) { // You can use closures to dynamically generate possibilities
            if ('black' === $combination['hair']) { // Then you have access to the current combination being built
                return 'brown';
            }
            return 'grey';
        }
    ]
];

foreach (combinations($data) as $combination) {
    printf('Hair: %s - Eyes: %s' . PHP_EOL, $combination['hair'], $combination['eyes']);
}

Output:

Hair: blond - Eyes: blue
Hair: blond - Eyes: green
Hair: blond - Eyes: grey
Hair: black - Eyes: blue
Hair: black - Eyes: green
Hair: black - Eyes: brown

Array output

Instead of using foreach you can dump all possibilities into an array.

Warning

This will dump all combinations in memory, so be careful with large datasets.

print_r(combinations($data)->asArray());

Output:

Array
(
    [0] => Array
        (
            [hair] => blond
            [eyes] => blue
        )

    [1] => Array
        (
            [hair] => blond
            [eyes] => green
        )

    [2] => Array
        (
            [hair] => blond
            [eyes] => grey
        )

    [3] => Array
        (
            [hair] => black
            [eyes] => blue
        )

    [4] => Array
        (
            [hair] => black
            [eyes] => green
        )

    [5] => Array
        (
            [hair] => black
            [eyes] => brown
        )

)

Combinations count

You can simply count how many combinations your data produce (this will not generate any combination):

use function BenTools\CartesianProduct\combinations;

$data = [
    'hair' => [
        'blond',
        'red',
    ],
    'eyes' => [
        'blue',
        'green',
        'brown',
    ],
    'gender' => [
        'male',
        'female',
    ]
];
var_dump(count(combinations($data))); // 2 * 3 * 2 = 12

Filtering combinations

You can filter combinations using the filter method. This is useful if you want to skip some combinations based on certain criteria:

use function BenTools\CartesianProduct\combinations;

$data = [
    'hair' => [
        'blond',
        'black'
    ],
    'eyes' => [
        'blue',
        'green',
    ]
];

foreach (combinations($data)->filter(fn (array $combination) => 'green' !== $combination['eyes']) as $combination) {
    printf('Hair: %s - Eyes: %s' . PHP_EOL, $combination['hair'], $combination['eyes']);
}

Map output

You can use the each method to transform each combination into a different format:

use App\Entity\Book;

use function BenTools\CartesianProduct\combinations;

$books = [
    'author' => ['Isaac Asimov', 'Arthur C. Clarke'],
    'genre' => ['Science Fiction', 'Fantasy'],
]

foreach (combinations($books)->each(fn (array $combination) => Book::fromArray($combination)) as $book) {
    assert($book instanceof Book);
}

Installation

PHP 8.2+ is required.

composer require bentools/cartesian-product

Performance test

The following example was executed on my Core i7 personnal computer with 8GB RAM.

use function BenTools\CartesianProduct\combinations;

$data = array_fill(0, 10, array_fill(0, 5, 'foo'));

$start = microtime(true);
foreach (combinations($data) as $c => $combination) {
    continue;
}
$end = microtime(true);

printf(
    'Generated %d combinations in %ss - Memory usage: %sMB / Peak usage: %sMB',
    ++$c,
    round($end - $start, 3),
    round(memory_get_usage() / 1024 / 1024),
    round(memory_get_peak_usage() / 1024 / 1024)
);

Output:

Generated 9765625 combinations in 1.61s - Memory usage: 0MB / Peak usage: 1MB

Unit tests

./vendor/bin/pest

Other implementations

th3n3rd/cartesian-product

patchranger/cartesian-iterator

Benchmark

See also

bentools/string-combinations

bentools/iterable-functions

Credits

Titus on StackOverflow - you really rock.

About

PHP - A simple, low-memory footprint function to generate all combinations from a multi-dimensionnal array.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.