Сгенерировать все возможные комбинации с помощью набора строк

Я пытаюсь создать все возможные комбинации набора строк, используя каждый максимум строки один раз.

  • Длина выходной строки не определена (максимальная длина – это количество заданных строк, так как вы можете использовать их только один раз)
  • Например, array('A','B') stringset array('A','B') будет генерировать A, B, AB, BA.
  • Например, array('ABC', 'Z') stringset array('ABC', 'Z') будет генерировать «ABC», «Z», «ZABC» и «ABCZ».
  • Строковый набор может иметь одинаковые записи, и выход не должен быть уникальным. Например, array('A', 'A') stringset array('A', 'A') будет генерировать 'A', 'A', 'AA', 'AA' ; (Мне действительно не нужны дубликаты, но я не хочу, чтобы вещи делались сложнее)

Я знаю, что 2 строки имеют 4 комбинации (2 => 4) и 3 => 15, 4 => 64, 5 => 325 …

Поскольку я не программист, я нашел это, по крайней мере, «сложным». Вложенные петли, которые скоро слишком сложны. Более простым решением может быть поиск шаблона в индексах массива со строками. Но это дает мне повторное использование строк …

  $strings = array('T','O','RS'); $num = 0; $stringcount = count($strings); $variations = array(0,1,4,15,64,325,1956,13699,109600,986409); for($i=0;$i<$variations[$stringcount];$i++){ $index = base_convert($num, 10, $stringcount); $array_of_indexes = str_split($index); $out=''; for($j=0;$j<count($array_of_indexes);$j++){ $out .= $strings[$array_of_indexes[$j]]; } echo $out . '<br />'; $num++; } 

Результат: T O RS OT OO ORS RST RSO RSRS OTT OTO OTRS OOT OOO OORS

Не очень много, много дубликатов + много действительных комбинаций не включены

Я знаю, что это решение не так во многих отношениях, но я не знаю с чего начать? Какие-либо предложения? Thx в Advance!

В математической терминологии вы запрашиваете все возможные непустые упорядоченные подмножества входного набора. В онлайн-энциклопедии целочисленных последовательностей число таких последовательностей появляется как последовательность A007526 – обратите внимание, что эта последовательность начинается с 4, 15, 64, 325 точно так же, как вы обнаружили.

Эта проблема допускает очень короткое, эффективное решение в Python, поэтому я собираюсь опубликовать это решение в первую очередь:

 def gen_nos(s): for i in sorted(s): yield i s.remove(i) for j in gen_nos(s): yield i+j s.add(i) 

Пример:

 >>> list(gen_nos(set(['a', 'b', 'c']))) ['a', 'ab', 'abc', 'ac', 'acb', 'b', 'ba', 'bac', 'bc', 'bca', 'c', 'ca', 'cab', 'cb', 'cba'] 

Обратите внимание, что sorted не является строго необходимой; он просто гарантирует, что вывод лексикографически отсортирован (в противном случае элементы повторяются в заданном порядке, что по существу произвольно).

Чтобы преобразовать это в PHP, мы должны по существу использовать рекурсивную функцию с дополнительным параметром массива для хранения результата:

 function gen_nos(&$set, &$results) { for($i=0; $i<count($set); $i++) { $results[] = $set[$i]; $tempset = $set; array_splice($tempset, $i, 1); $tempresults = array(); gen_nos($tempset, $tempresults); foreach($tempresults as $res) { $results[] = $set[$i] . $res; } } } 

Пример:

 $results = array(); $set = array("a", "b", "c"); gen_nos($set, $results); var_dump($results); 

производит

 array(15) { [0]=> string(1) "a" [1]=> string(2) "ab" [2]=> string(3) "abc" [3]=> string(2) "ac" [4]=> string(3) "acb" [5]=> string(1) "b" [6]=> string(2) "ba" [7]=> string(3) "bac" [8]=> string(2) "bc" [9]=> string(3) "bca" [10]=> string(1) "c" [11]=> string(2) "ca" [12]=> string(3) "cab" [13]=> string(2) "cb" [14]=> string(3) "cba" } 

Вот моя реализация, которую я написал довольно долго, используя базовый математический определитель комбинации и перестановки. Может быть, это может помочь.

 <?php /** * Generate all the combinations of $num elements in the given array * * @param array $array Given array * @param int $num Number of elements ot chossen * @param int $start Starter of the iteration * @return array Result array */ function combine($array, $num, $start = 0) { static $level = 1; static $result = array(); $cnt = count($array); $results = array(); for($i = $start;$i < $cnt;$i++) { if($level < $num ) { $result[] = $array[$i]; $start++; $level++; $results = array_merge($results, combine($array, $num, $start)); $level--; array_pop($result); } else { $result[] = $array[$i]; $results[] = $result; array_pop($result); } } return $results; } /** * Generate all the permutations of the elements in the given array */ function permute($array) { $results = array(); $cnt = count($array); for($i=0;$i<$cnt;$i++) { $first = array_shift($array); if(count($array) > 2 ) { $tmp = permute($array); } elseif(count($array) == 2) { $array_ = $array; krsort($array_); $tmp = array($array, $array_); } elseif(count($array) == 1) { $tmp = array($array); } elseif(count($array) == 0) { $tmp = array(array()); } foreach($tmp as $k => $t) { array_unshift($t, $first); $tmp[$k] = $t; } $results = array_merge($results, $tmp); array_push($array, $first); } return $results; } $strings = array('T', 'O', 'RS'); $strings_count = count($strings); $combinations = array(); for ($i = 1; $i <= $strings_count; $i++) { $combination = combine($strings, $i, 0); $combinations = array_merge($combinations, $combination); } $permutations = array(); foreach($combinations as $combination) { $permutation = permute($combination); $permutations = array_merge($permutations, $permutation); } print_r($combinations); print_r($permutations); 

Вот моя наивная рекурсивная реализация:

 <?php // Lists all ways to choose X from an array function choose($x, array $arr) { $ret = array(); if ($x === 0) { // I don't think this will come up. return array(); } else if ($x === 1) { foreach ($arr as $val) { $ret[] = array($val); } } else { $already_chosen = choose($x - 1, $arr); for ($i = 0, $size_i = sizeof($arr); $i < $size_i; $i++) { for ($j = 0, $size_j = sizeof($already_chosen); $j < $size_j; $j++) { if (!in_array($arr[$i], $already_chosen[$j])) { $ret[] = array_merge( array($arr[$i]), $already_chosen[$j] ); } } } } return $ret; } function choose_all($arr) { for ($i = 1, $size = sizeof($arr); $i <= $size; $i++) { foreach (choose($i, $arr) as $val) { echo implode(":", $val).PHP_EOL; } } } choose_all(array( "A", "B", )); echo "--".PHP_EOL; choose_all(array( "ABC", "Z", )); echo "--".PHP_EOL; choose_all(array( 'T', 'O', 'RS' )); 

(Не знаю, что я сделал, конечно)

http://codepad.org/5OKhsCJg

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

(Я никогда не делал никакого PHP напрямую, поэтому я не хочу сообщать вам о некорректном (или взломанном) решении, но, надеюсь, это поможет привести вас к правильному пути)!