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:
First assign the arrays keys to a variable with
array_keys()
, e.g.$keys = array_keys($data);
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 with1
, then1_5
and then finally1_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
How to Use MySQLi Prepared Statements
How to Convert a Pdf Document to a Preview Image in PHP
"Date(): It Is Not Safe to Rely on the System'S Timezone Settings..."
How to Get the Cookies from a PHP Curl into a Variable
Fatal Error: Uncaught Error: Call to Undefined Function MySQL_Connect()
Using a String Path to Set Nested Array Data
Access Array Returned by a Function in PHP
Is There a "Nullsafe Operator" in PHP
Why Can't I Run Two MySQLi Queries? The Second One Fails
How to Get the Query Builder to Output Its Raw SQL Query as a String
Best Way to Avoid Duplicate Entry into MySQL Database
How to Create a Comma-separated List from an Array in PHP
Convert Time in Hh:Mm:Ss Format to Seconds Only
Send Email from Localhost Running Xammp in PHP Using Gmail Mail Server
How to Make a Calculator in PHP
MySQLi Update Throwing Call to a Member Function Bind_Param() Error