I have created a filter system, You can filter results on multiple taxonomies.
For example: Show all news articles and videos that are in the categories gaming and productivity and with the tag hardware, you could make a selection like this
Content Type [x] news article [x] video [ ] opinion Category [x] gaming [x] productivity [ ] music Tags [x] hardware [ ] software
This can be represented in an array like this:
[ [ 'news article', 'video' ], [ 'gaming', 'productivity' ], [ 'hardware' ] ];
Now basically what I want is to get an array containing all possible combinations. So it would start like this:
[ [ [], [], [], ], // no selections [ ['news article'], [], [], ], // only news article selected [ ['video'], [], [], ], [ ['opinion'], [], [], ], [ ['news article, video'], [], [], ], [ ['news article, opinion'], [], [], ], [ ['video, opinion'], [], [], ], [ ['news article'], ['gaming'], [], ], ... [ ['news article', 'video', 'opinion'], ['gaming', 'productivity', 'music'], ['hardware','software'], ], ];
This seems like a common enough problem, but the only combination algorithms I found so far are ones that make combinations with only one element from each array. I realize that the set of combinations that I want to create would become outrageously large incredibly fast, but is there a known approach or PHP function that I could use to generate an array like this?
Advertisement
Answer
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);