Получить все перестановки массива PHP?

Учитывая массив строк PHP, например:

['peter', 'paul', 'mary'] 

Как сгенерировать все возможные перестановки элементов этого массива? то есть:

 peter-paul-mary peter-mary-paul paul-peter-mary paul-mary-peter mary-peter-paul mary-paul-peter 

 function pc_permute($items, $perms = array()) { if (empty($items)) { echo join(' ', $perms) . "<br />"; } else { for ($i = count($items) - 1; $i >= 0; --$i) { $newitems = $items; $newperms = $perms; list($foo) = array_splice($newitems, $i, 1); array_unshift($newperms, $foo); pc_permute($newitems, $newperms); } } } $arr = array('peter', 'paul', 'mary'); pc_permute($arr); 

или

 function pc_next_permutation($p, $size) { // slide down the array looking for where we're smaller than the next guy for ($i = $size - 1; $p[$i] >= $p[$i+1]; --$i) { } // if this doesn't occur, we've finished our permutations // the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1) if ($i == -1) { return false; } // slide down the array looking for a bigger number than what we found before for ($j = $size; $p[$j] <= $p[$i]; --$j) { } // swap them $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp; // now reverse the elements in between by swapping the ends for (++$i, $j = $size; $i < $j; ++$i, --$j) { $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp; } return $p; } $set = split(' ', 'she sells seashells'); // like array('she', 'sells', 'seashells') $size = count($set) - 1; $perm = range(0, $size); $j = 0; do { foreach ($perm as $i) { $perms[$j][] = $set[$i]; } } while ($perm = pc_next_permutation($perm, $size) and ++$j); foreach ($perms as $p) { print join(' ', $p) . "\n"; } 

http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm

Мне нужно было что-то похожее и нашел этот пост, глядя. Приземлился, написав следующее, что делает работу.

С 8 элементами он работает довольно быстро (немного быстрее, чем примеры, которые я нашел в Интернете), но выходите за рамки этого, и время работы быстро растет. Если вам нужно только выводить результаты, это может быть сделано быстрее, а использование памяти значительно уменьшится.

 print_r(AllPermutations(array('peter', 'paul', 'mary'))); function AllPermutations($InArray, $InProcessedArray = array()) { $ReturnArray = array(); foreach($InArray as $Key=>$value) { $CopyArray = $InProcessedArray; $CopyArray[$Key] = $value; $TempArray = array_diff_key($InArray, $CopyArray); if (count($TempArray) == 0) { $ReturnArray[] = $CopyArray; } else { $ReturnArray = array_merge($ReturnArray, AllPermutations($TempArray, $CopyArray)); } } return $ReturnArray; } 

Обратите внимание, что число перестановок является факториалом количества элементов в массиве. Для 3 предметов есть 6 перестановок, для 4 – 24, для 5 – 120, для 6 – 720 и т. Д.

Это делает то, что вам нужно, на месте, то есть без выделения дополнительной памяти. Он сохраняет полученные перестановки в массиве $ results. Я довольно уверен, что это быстрый способ решить эту задачу.

 <?php function computePermutations($array) { $result = []; $recurse = function($array, $start_i = 0) use (&$result, &$recurse) { if ($start_i === count($array)-1) { array_push($result, $array); } for ($i = $start_i; $i < count($array); $i++) { //Swap array value at $i and $start_i $t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t; //Recurse $recurse($array, $start_i + 1); //Restore old order $t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t; } }; $recurse($array); return $result; } $results = computePermutations(array('foo', 'bar', 'baz')); print_r($results); 

Это работает в PHP> 5.4. Я использовал анонимную функцию для рекурсии, чтобы очистить интерфейс основной функции.

Я немного расширил ответ Джека

 function pc_permute($items, $perms = [],&$ret = []) { if (empty($items)) { $ret[] = $perms; } else { for ($i = count($items) - 1; $i >= 0; --$i) { $newitems = $items; $newperms = $perms; list($foo) = array_splice($newitems, $i, 1); array_unshift($newperms, $foo); $this->pc_permute($newitems, $newperms,$ret); } } return $ret; } 

Это фактически вернет массив со всеми возможными перестановками.

 $options = ['startx','starty','startz','endx','endy','endz']; $x = $this->pc_permute($options); var_dump($x); [0]=> array(6) { [0]=> string(6) "startx" [1]=> string(6) "starty" [2]=> string(6) "startz" [3]=> string(4) "endx" [4]=> string(4) "endy" [5]=> string(4) "endz" } [1]=> array(6) { [0]=> string(6) "starty" [1]=> string(6) "startx" [2]=> string(6) "startz" [3]=> string(4) "endx" [4]=> string(4) "endy" [5]=> string(4) "endz" } [2]=> array(6) { [0]=> string(6) "startx" [1]=> string(6) "startz" [2]=> string(6) "starty" [3]=> string(4) "endx" [4]=> string(4) "endy" [5]=> string(4) "endz" } [3]=> array(6) { [0]=> string(6) "startz" [1]=> string(6) "startx" [2]=> string(6) "starty" [3]=> string(4) "endx" [4]=> string(4) "endy" [5]=> string(4) "endz" } [4]=> array(6) { [0]=> string(6) "starty" [1]=> string(6) "startz" [2]=> string(6) "startx" [3]=> string(4) "endx" [4]=> string(4) "endy" [5]=> string(4) "endz" } [5]=> array(6) { [0]=> string(6) "startz" [1]=> string(6) "starty" [2]=> string(6) "startx" [3]=> string(4) "endx" [4]=> string(4) "endy" [5]=> string(4) "endz" } [6]=> ................ a lot more 

Я нашел более полезным получить массив обратно вместо строки. Тогда это зависит от используемого приложения, как обращаться с resutls (чтобы присоединиться к ним или что-то еще)

Простая версия с рекурсией и без лишних аргументов:

 function permuteArray(array $input) { $input = array_values($input); // permutation of 1 value is the same value if (count($input) === 1) { return array($input); } // to permute multiple values, pick a value to put in the front and // permute the rest; repeat this with all values of the original array $result = []; for ($i = 0; $i < count($input); $i++) { $copy = $input; $value = array_splice($copy, $i, 1); foreach (permuteArray($copy) as $permutation) { array_unshift($permutation, $value[0]); $result[] = $permutation; } } return $result; } 

Этот алгоритм хорош и поучителен в том, как вы это сделаете на бумаге, но в противном случае очень неэффективно, поскольку он вычисляет одни и те же перестановки несколько раз. Нельзя сказать, что для вычисления перестановок больших массивов очень непрактично, поскольку пространство и число вычислений экспоненциально растут.