How to Generate in PHP All Combinations of Items in Multiple Arrays

How to generate in PHP all combinations of items in multiple arrays

Here is recursive solution:

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;
}

print_r(
combinations(
array(
array('A1','A2','A3'),
array('B1','B2','B3'),
array('C1','C2')
)
)
);

How to get all combinations from multiple arrays?

How many combinations are there?

So first the question how many combinations are there? And the answer is you have to multiply the amount of every array with each other.

So (c = amount1):

carray 1 * carray 2 * ... * carray n

And specific for your example:

carray 1 * carray 2 * carray 3 = 2 * 2 * 2 = 8

*1 And if you wonder why I chose c for amount, because of the function count() in php

Getting all combinations together

How do we get now all combinations with the amount of arrays, which we have?

We loop through all our combinations, which we already have(Starting off with one combination, an "empty combination" ($combinations = [[]];)), and for each combination we go through our next data array and combine each combination with each input data to a new combination.

Now we do this until we get the desired length for each combination.

So as an example:

Array with the elements (Empty array is '[]'):

[
[1, 2],
[3, 4]
]



                               //↓ new combinations for the next iteration

array NAN*:

Combinations:
- [] │ -> []

array 1 [1,2]: ┌─────────────┤
│ │
Combinations: v v
- [] + 1 │ -> [1]
- [] + 2 │ -> [2]

array 2 [3,4]: ┌─────────────┤
│ │
Combinations: v v
- [] + 3 │ -> [3]
- [] + 4 │ -> [4]
- [1] + 3 │ -> [1,3] //desired length 2 as we have 2 arrays
- [1] + 4 │ -> [1,4] //desired length 2 as we have 2 arrays
- [2] + 3 │ -> [2,3] //desired length 2 as we have 2 arrays
- [2] + 4 │ -> [2,4] //desired length 2 as we have 2 arrays
//↑ All combinations here

* NAN: not a number

So as you can see in the above example we now have all combinations with the length of the amount of all arrays which we have.

But to get only the combinations with the desired length we are overwriting the result array each iteration, so that at the end only the combinations with the expected length are in the results array.

Code:

<?php

$array1 = array(1,2);
$array2 = array(4,5);
$array3 = array(7,8);


$combinations = [[]];
$data = [
$array1,
$array2,
$array3,
];
$length = count($data);

for ($count = 0; $count < $length; $count++) {
$tmp = [];
foreach ($combinations as $v1) {
foreach ($data[$count] as $v2)
$tmp[] = array_merge($v1, [$v2]);

}
$combinations = $tmp;
}

print_r($combinations);

?>

output:

Array
(
[0] => Array
(
[0] => 1
[1] => 4
[2] => 7
)
//...
[7] => Array
(
[0] => 2
[1] => 5
[2] => 8
)

)

For associative arrays you only have to do a slight modification, which is:

  1. First assign the arrays keys to a variable with array_keys(), e.g.

    $keys = array_keys($data);
  2. Use the keys in the second foreach loop to access the data array, means from:

    foreach ($data[$count] as $v2)

    to:

    foreach ($data[$keys[$count]] as $v2)

How to generate in PHP all possible selections of items in multiple arrays to cache a filter system

First, use the following function to generate all possible choices:

function array_combine_values($array)
{
$len = count($array);
$result = [];
for($i = 0; $i < pow(2, $len); $i++) {
$row = [];
$indexes = str_split(str_pad(decbin($i), $len, '0', STR_PAD_LEFT));
foreach($indexes as $key => $index) {
if ($index) $row[] = $array[$key];
}
$result[] = $row;
}
return $result;
}

Example:

print_r(array_combine_values(['a', 'b']));

Output:

Array
(
[0] => Array
(
)
[1] => Array
(
[0] => b
)
[2] => Array
(
[0] => a
)
[3] => Array
(
[0] => a
[1] => b
)
)

Second, the function of the Cartesian product of arrays:

function array_cartesian_product($array)
{
if (empty($array)) return [[]];

$column = array_shift($array);
$cartesian = array_cartesian_product($array);

$result = [];
foreach ($column as $row) {
foreach ($cartesian as $item) {
array_unshift($item, $row);
$result[] = $item;
}
}
return $result;
}

Example:

print_r(array_cartesian_product([['a', 'b'], ['c', 'd']]));

Output:

Array
(
[0] => Array
(
[0] => a
[1] => c
)
[1] => Array
(
[0] => a
[1] => d
)
[2] => Array
(
[0] => b
[1] => c
)
[3] => Array
(
[0] => b
[1] => d
)
)

Usage in your case:

$selections = array( 
['news article', 'video', 'opinion'],
['gaming', 'productivity', 'music'],
['hardware','software']
);

$result = [];

foreach($selections as $items) {
$result[] = array_combine_values($items);
}

$result = array_cartesian_product($result);

print_r($result);

Generate all combinations of elements between arrays

<?php 


$array1 = [1,2,3,4];
$array2 = [5,6,7];
$array3 = [8,9,10,11,12];

$collection = [$array1,$array2,$array3];

$result = $collection[0];
array_shift($collection);
foreach($collection as $each_array){
$temp = [];
foreach($result as $each_sub_result){
foreach($each_array as $each_item){
$temp[] = $each_sub_result."_".$each_item;
}
}
$result = $temp;
}

print_r($result);

Algorithm:

  • We collect all arrays in our $collection variable.
  • Now, we loop over all elements of our $collection variable where each individual item is an array.
  • I have done an array_shift() since we are assigning first element of $collection to $result(so we don't want to iterate over them again).
  • We maintain $temp to store temporary results. Note that we use $result also to store temporary results, so that we can iterate over it and get new temporary results. By temporary, I mean building the final array. For example: It starts with 1, then 1_5 and then finally 1_5_8.
  • After the looping completes, we will have our final answer in $result.

PHP - Generate all combinations of items in array

You can of course with permutation libraries, but that you have to sort every single subarray alphabetically and remove duplicates with array_unique().

Or you might try to be more cost efficient:

$myarray = array(
'red', 'yellow', 'green', 'blue'
);

$result = [];

while ($item = array_pop($myarray)) {
foreach($myarray as $couple) {
$result[] = [$item, $couple];
}
}

print_r($result);

First thing is you are reducing a source array every step, and every context should have its copy of array. It means, that if you are willing to encapsulate mechanics in recursive function to generate more that two member arrays, you need to prevent their internal copies from being changed by anything else than array_pop of their own context.

For the explanation of code above, I'm popping one element off the top of source array, and than iterate over survived element to couple a pair. This way I wont pair "red" with "red", and I wont produce disordered duplicates.

Generate all combination from two arrays in php

You need to convert your array to this,

$a    = ["abc", "defs", "ghi"];
$b = ["abcs", "def", "ghis"];
$temp = array_map(null, $a, $b); // this conversion we call it transposing of array
function combinations($arrays)
{
$result = [];
$arrays = array_values($arrays);
$sizeIn = sizeof($arrays);
$size = $sizeIn > 0 ? 1 : 0;
foreach ($arrays as $array) {
$size = $size * sizeof($array);
}
for ($i = 0; $i < $size; $i++) {
$result[$i] = [];
for ($j = 0; $j < $sizeIn; $j++) {
array_push($result[$i], current($arrays[$j]));
}
for ($j = ($sizeIn - 1); $j >= 0; $j--) {
if (next($arrays[$j])) {
break;
} elseif (isset($arrays[$j])) {
reset($arrays[$j]);
}
}
}
return $result;
}
$res = combinations($temp);
// imploding all the values internally with space
$temp = array_map(function($item){
return implode(" ", $item);
},$res);
// looping to show the data
foreach($temp as $val){
echo $val."\n";
}

Once you convert your array using array_map, then I used help of this.

Demo.

Output

abc defs ghi
abc defs ghis
abc def ghi
abc def ghis
abcs defs ghi
abcs defs ghis
abcs def ghi
abcs def ghis

How can I generate all unique combinations of multiple array's with optionals?

It seems that answer is much more simple than understanding the problem.
You need no change in procedure - just include 'null' as possible value in optional arrays. It would mean that part wasn't included.

This way there will be arrays with null values returned, but their indexes will represent source. Taking array below for example:

$data = array(
'Chassis' => array(0, 1, 2),
'Mainboard' => array(3, 4, 5),
'PSU' => array(6, 7, 8),
'Disk' => array(null, 9, 10),
'GFX' => array(null, 11, 12),
'Memory' => array(null, 13, 14, 15)
);

One of the results would be: [0,3,6,null,11,null]* which means that GFX was included.

You could filter that result if you don't want empty values with

array_filter($combination, 'is_int')

'is_int' param is needed only to handle 0 correctly. If 0 is not valid id then you might skip it (and may use 0 instead of null then)

*) actually last element jumps to first position because of array_merge() args order

Edit:

This generator itself is ~35% faster (same memory usage) and doesn't require filtering which overall becomes twice as fast:

function generateCombinations(array $array) {
foreach (array_pop($array) as $id) {
if (empty($array)) {
yield isset($id) ? [$id] : [];
continue;
}

foreach (generateCombinations($array) as $combination) {
if (isset($id)) { $combination[] = $id; }
yield $combination;
}
}
}

How to generate in PHP all combinations of items in multiple arrays

Here is recursive solution:

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;
}

print_r(
combinations(
array(
array('A1','A2','A3'),
array('B1','B2','B3'),
array('C1','C2')
)
)
);


Related Topics



Leave a reply



Submit