PHP 2D Array выводит все комбинации

У меня была эта проблема, сгибающая мой разум какое-то время (голова холода тоже не помогает!), В основном у меня есть PHP-массив, который выглядит следующим образом:

$array[0][0] = 'apples'; $array[0][1] = 'pears'; $array[0][2] = 'oranges'; $array[1][0] = 'steve'; $array[1][1] = 'bob'; 

И я хотел бы иметь возможность производить из этого таблицы все возможные комбинации, но без повторения каких-либо комбинаций (независимо от их положения), поэтому, например, это будет выводить

 Array 0 Array 1 apples steve apples bob pears steve pears bob 

Но я хотел бы, чтобы это могло работать с максимально возможным количеством различных массивов.

это называется «декартовым продуктом», страницей php man на массивах. http://php.net/manual/en/ref.array.php показывает некоторые реализации (в комментариях).

и вот еще один:

 function array_cartesian() { $_ = func_get_args(); if(count($_) == 0) return array(array()); $a = array_shift($_); $c = call_user_func_array(__FUNCTION__, $_); $r = array(); foreach($a as $v) foreach($c as $p) $r[] = array_merge(array($v), $p); return $r; } $cross = array_cartesian( array('apples', 'pears', 'oranges'), array('steve', 'bob') ); print_r($cross); 

Вы ищете декартовое произведение массивов, и есть пример на сайте php-массивов: http://php.net/manual/en/ref.array.php

Syom скопировал http://www.php.net/manual/en/ref.array.php#54979, но я адаптировал его, чтобы стать ассоциативной версией:

 function array_cartesian($arrays) { $result = array(); $keys = array_keys($arrays); $reverse_keys = array_reverse($keys); $size = intval(count($arrays) > 0); foreach ($arrays as $array) { $size *= count($array); } for ($i = 0; $i < $size; $i ++) { $result[$i] = array(); foreach ($keys as $j) { $result[$i][$j] = current($arrays[$j]); } foreach ($reverse_keys as $j) { if (next($arrays[$j])) { break; } elseif (isset ($arrays[$j])) { reset($arrays[$j]); } } } return $result; } 

Мне нужно было сделать то же самое, и я попробовал предыдущие решения, размещенные здесь, но не мог заставить их работать. Я получил образец от этого умного парня http://www.php.net/manual/en/ref.array.php#54979 . Тем не менее, его образец не справился с концепцией отсутствия повторяющихся комбинаций. Поэтому я включил эту часть. Вот моя модифицированная версия, надеюсь, что это поможет:

 $data = array( array('apples', 'pears', 'oranges'), array('steve', 'bob') ); $res_matrix = $this->array_cartesian_product( $data ); foreach ( $res_matrix as $res_array ) { foreach ( $res_array as $res ) { echo $res . " - "; } echo "<br/>"; } function array_cartesian_product( $arrays ) { $result = array(); $arrays = array_values( $arrays ); $sizeIn = sizeof( $arrays ); $size = $sizeIn > 0 ? 1 : 0; foreach ($arrays as $array) $size = $size * sizeof( $array ); $res_index = 0; for ( $i = 0; $i < $size; $i++ ) { $is_duplicate = false; $curr_values = array(); for ( $j = 0; $j < $sizeIn; $j++ ) { $curr = current( $arrays[$j] ); if ( !in_array( $curr, $curr_values ) ) { array_push( $curr_values , $curr ); } else { $is_duplicate = true; break; } } if ( !$is_duplicate ) { $result[ $res_index ] = $curr_values; $res_index++; } for ( $j = ( $sizeIn -1 ); $j >= 0; $j-- ) { $next = next( $arrays[ $j ] ); if ( $next ) { break; } elseif ( isset ( $arrays[ $j ] ) ) { reset( $arrays[ $j ] ); } } } return $result; } 

Результат будет примерно таким:
яблоки – steve
яблоки – боб
груши – steve
груши – боб
апельсины – steve
апельсины – боб

Если вы массив данных выглядит примерно так:

  $data = array( array('Amazing', 'Wonderful'), array('benefit', 'offer', 'reward'), array('Amazing', 'Wonderful') ); 

Затем он напечатает что-то вроде этого:

Удивительно – полезно – Замечательно
Удивительный – предложение – Замечательный
Удивительный – награда – Замечательный
Чудесный – полезный – Удивительный
Замечательный – предложение – Удивительный
Чудесный – награда – Удивительный

 foreach($parentArray as $value) { foreach($subArray as $value2) { $comboArray[] = array($value, $value2); } } 

Не судите меня ..

Это работает, я думаю – хотя после написания я понял, что он очень похож на то, что другие положили, но он дает вам массив в запрошенном формате. Извините за плохое имя переменной.

 $output = array(); combinations($array, $output); print_r($output); function combinations ($array, & $output, $index = 0, $p = array()) { foreach ( $array[$index] as $i => $name ) { $copy = $p; $copy[] = $name; $subIndex = $index + 1; if (isset( $array[$subIndex])) { combinations ($array, $output, $subIndex, $copy); } else { foreach ($copy as $index => $name) { if ( !isset($output[$index])) { $output[$index] = array(); } $output[$index][] = $name; } } } } 

@ user187291

Я изменил это, чтобы

 function array_cartesian() { $_ = func_get_args(); if (count($_) == 0) return array(); $a = array_shift($_); if (count($_) == 0) $c = array(array()); else $c = call_user_func_array(__FUNCTION__, $_); $r = array(); foreach($a as $v) foreach($c as $p) $r[] = array_merge(array($v), $p); return $r; } 

поэтому он возвращает этот важный массив (тот же результат, что и никакие комбинации), когда вы передаете 0 аргументов.

Только заметил это, потому что я использую его как

 $combos = call_user_func_array('array_cartesian', $array_of_arrays); 
 function array_comb($arrays) { $result = array(); $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] = array(); 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; } 

Мне пришлось делать комбинации из вариантов продукта. Это решение использует рекурсию и работает с 2D-массивом:

 function options_combinations($options) { $result = array(); if (count($options) <= 1) { $option = array_shift($options); foreach ($option as $value) { $result[] = array($value); } } else { $option = array_shift($options); $next_option = options_combinations($options); foreach ($next_option as $next_value) { foreach ($option as $value) { $result[] = array_merge($next_value, array($value)); } } } return $result; } $options = [[1,2],[3,4,5],[6,7,8,9]]; $c = options_combinations($options); foreach ($c as $combination) { echo implode(' ', $combination)."\n"; } 

Элегантная реализация на основе собственной функции Python itertools.product

 function direct_product(array ...$arrays) { $result = [[]]; foreach ($arrays as $array) { $tmp = []; foreach ($result as $x) { foreach ($array as $y) { $tmp[] = array_merge($x, [$y]); } } $result = $tmp; } return $result; } 

В базе данных MySQL это будет выглядеть так:

 SELECT * FROM `options`, `groups` 

Это все 🙂