Skip to content
Advertisement

Form array of delimited strings with all combinations of values from 3 flat arrays

I want to do something like this:

$product = $productdata['productinfo']['product']; //canvas 

$availableSizes = $productdata["productinfo"]["sizes"]; // 8x10 and 10x10

$material = array("matte","luster");

I want to merge combinations of all values so that the result would be 4 string values in a flat array:

Array
(
    [0] => canvas_8x10_matte
    [1] => canvas_8x10_luster
    [2] => canvas_10x10_matte
    [3] => canvas_10x10_luster
)

I tried something like this:

$result = array_map(
    function ($x, $y) {
        return $product . "_" . $x . '_' . $y;
    },
    $availableSizes,
    $material
);

but it only brings me two values:

Array
(
    [0] => _8x10_matte
    [1] => _12x12_luster
)

And the $product variable seems to be unavailable. How to make it available in the array_map() scope?

Advertisement

Answer

array_map() accepts a callable as the first parameter, so $product will not be available in whatever is called due to variable scope. You are going to want to let your anonymous function know to use the global version of $product.

$result = array_map(function ($x, $y) { global $product; return $product . "_" . $x . '_' . $y; }, $availableSizes, $material);

This way the parser knows to look outside the function to find the data you are asking it for.

An even better way is to use inheritance to allow the function to inherit the variables scope from its parent.

$result = array_map(function ($x, $y) use ($product) { return $product . "_" . $x . '_' . $y; }, $availableSizes, $material);

Got tunnel vision on the second part of the question, that I missed the first part. You’re only getting the 2 instead of the 4 you are looking for, because array_map passes the array elements in parallel.

Usually when using two or more arrays, they should be of equal length because the callback function is applied in parallel to the corresponding elements.

Now if both arrays are only ever 2 elements in length, you could run a second array_map with the arrays called in reverse order, also reversing $x and $y in your return to keep text order. Then merge both results into one array. But that will break as soon as either array grows beyond 2 elements, and is just messy to maintain.

Try this. Lets loop over your first array, and run the array_map on just the second array, merging the results. Replace your entire $result = array_map(); line with this block.

$result = [];
foreach ($availableSizes as $v) {
    $result = array_merge($result, array_map(function ($x) use ($product, $v) {return $product . '_' . $v . '_' . $x;}, $material) );
}
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement