1

I have small difficulties to convert an array as I want, need some help from pros.

I have an array like that :

$inputs = array(
    'size' => array(
        's' => 's',
        'm' => 'm',
        'l' => 'l',
    ),
    'color' => array(
        'red' => 'red',
        'blue' => 'blue',
    ),
    'option' => 'option 1',
);

From this values, I need to create an array that combine all possibilities, like that :

$possibilities = array(
    0 => array('size' => 's', 'color' => 'red', 'option' => 'option 1'),
    1 => array('size' => 'm', 'color' => 'red', 'option' => 'option 1'),
    2 => array('size' => 'l', 'color' => 'red', 'option' => 'option 1'),
    3 => array('size' => 's', 'color' => 'blue', 'option' => 'option 1'),
    4 => array('size' => 'm', 'color' => 'blue', 'option' => 'option 1'),
    5 => array('size' => 'l', 'color' => 'blue', 'option' => 'option 1'),

);

I precise that I'm on laravel so I can use the collection methods, but even with this helpers methods, I can't find a way to obtain the $possibilities array I want.

The original array is dynamic (can have more options with different label names), so I need something that is able to work no matter the size of the array neither the name of the labels.

milo526
  • 5,012
  • 5
  • 41
  • 60
Alex
  • 13
  • 3
  • 1
    Welcome, can you please post the code you already have? – brombeer Sep 19 '18 at 08:11
  • 1
    This doesn't completely solve your question, since `option 1` is a string rather than an array, but it's something you can easily base your code on to get it working: https://stackoverflow.com/questions/6311779/finding-cartesian-product-with-php-associative-arrays – Joel Hinz Sep 19 '18 at 08:12
  • @JoelHinz Thanks, your example seems close to mine, will try if I can base my code on this. – Alex Sep 19 '18 at 09:18

2 Answers2

0
$output = array();
foreach($inputs['size'] as $size)
{
    foreach($inputs['colour'] as $colour)
    {
        foreach($inputs['option'] as $option)
        {
            $output[] = array('size' => $size, 'colour' => $colour, 'option' => $option);
        }
    }
}
return $output;

Update :

$collection = collect($inputs[0]);
array_shift($inputs);
$matrix = $collection->crossJoin($inputs);
$matrix->all();

Update :

$collection = collect(array_shift($inputs));
$matrix = $collection->crossJoin($inputs);
$matrix->all();

Update :

use this function

function combinations($arrays, $i = 0) {
    if (!isset($arrays[$i])) {
        return array();
    }
    if ($i == count($arrays) - 1) {
        return $arrays[$i];
    }

    // get combinations from subsequent arrays
    $tmp = combinations($arrays, $i + 1);

    $result = array();

    // concat each array from tmp with each element from $arrays[$i]
    foreach ($arrays[$i] as $v) {
        foreach ($tmp as $t) {
            $result[] = is_array($t) ? 
                array_merge(array($v), $t) :
                array($v, $t);
        }
    }

    return $result;
}
syam
  • 892
  • 8
  • 19
  • @siam Good input, but the labels are variables in size and in names. So I can't rely on fixed keys. – Alex Sep 19 '18 at 09:14
  • Your code seems very elegant, but I have an error that says that $input[0] is undefined offset. Not sure what is the collection you try to create using inputs[0] – Alex Sep 19 '18 at 10:18
  • actually, i am collecting first array of the inputs you have, and cross joining it with rest of the arrays in inputs you have – syam Sep 19 '18 at 11:11
  • Doesn't work, the latest update give me that array as result : Array ( [0] => Array ( [0] => m [1] => Array ( [red] => red [blue] => blue ) ) [1] => Array ( [0] => l [1] => Array ( [green] => vert [blue] => bleu ) ) ) – Alex Sep 19 '18 at 12:13
  • its not working because of keys i think, check documentation in laravel for crossJoin, it tries to achieve what you want – syam Sep 19 '18 at 12:22
  • what you are looking for is cartesian product, check this package https://github.com/bpolaszek/cartesian-product and https://stackoverflow.com/questions/6311779/finding-cartesian-product-with-php-associative-arrays – syam Sep 19 '18 at 14:54
0

Please try this, I hope it'll help you.

<?php

$inputs = array(
    'size' => array(
        's' => 's',
        'm' => 'm',
        'l' => 'l',
    ),
    'color' => array(
        'red' => 'red',
        'blue' => 'blue',
    ),
    'option' => 'option 1',
);
$combinations = [[]];
$length = count($inputs);

foreach (array_keys($inputs) as $key) {
    $tmp = [];
    foreach ($combinations as $v1) {
        if (is_array($inputs[$key])) {
            foreach ($inputs[$key] as $v2) {
                $tmp[] = array_merge($v1, [$key => $v2]);
            }
        } else {
            $tmp[] = array_merge($v1, [$key => $inputs[$key]]);
        }
    }
    $combinations = $tmp;
}
echo "<pre>";
print_r($combinations);

?>
  • Wow, your code works like a charm ! I'm still interested by a laravel collection solution cause it could be more elegant with the right methods at the right place, but it works really well ! – Alex Sep 19 '18 at 12:25