此问题与上述建议的问题不重复。标题可能声音类似,但其答案绝不会导致结果中描述的结果问题如下。
我很难以递归方式迭代未知长度的数组来创建独特的字符串组合。你能帮忙吗?
目标是获取foo bar
之类的字符串,并从此字符串创建唯一的组合:
foo
bar
bar_foo (alphabetized to make unique combinations, not permutations)
另一个例子:
car bar add
应该返回:
add
add_bar
add_car
add_bar_car
bar
bar_car
car
这是我的进步:
function string_builder($length) {
$arrWords = array('add','bar','car','dew','eat','fat','gym','hey','ink','jet','key','log','mad','nap','odd','pal','qat','ram','saw','tan','urn','vet','wed','xis','yap','zoo');
$arr = array();
for ($i=0; $i < $length; $i++) {
$arr[] = $arrWords[$i];
}
return implode(' ', $arr);
}
function get_combinations($string) {
$combinations = array(); // put all combinations here
$arr = explode(' ',$string);
$arr = array_unique($arr); // only unique words are important
sort($arr); // alphabetize to make unique combinations easier (not permutations)
$arr = array_values($arr); // reset keys
for ($i=0; $i < count($arr); $i++) {
// this is where I'm stuck
// how do I loop recursively through all possible combinations of an array?
}
return $combinations;
}
// Test it!
for ($i=1; $i < 26; $i++) {
$string = string_builder($i);
$combinations = get_combinations($string);
echo $i . " words\t" . count($combinations) . " combinations\t" . $string . "\n";
// print_r($combinations);
}
另一次尝试:
function getCombinations2($str, $min_length = 2) {
$words = explode(' ', $str);
$combinations = array();
$len = count($words);
for ($a = $min_length; $a <= $min_length; $a++) {
for ($pos = 0; $pos < $len; $pos ++) {
if(($pos + $a -1) < $len) {
$tmp = array_slice($words, $pos, $a);
sort($tmp);
$tmp = implode('_',$tmp);
$combinations[] = $tmp;
}
}
}
$combinations = array_unique($combinations);
return $combinations;
}
当您打印出组合并寻找应该存在的几个组合时,您可以知道自己已经成功(例如,&#34; fat_zoo&#34;,&#34; car_tan&#34;) 。我的两次尝试都会展示其中的几个,但绝不是全部。
答案 0 :(得分:3)
您正在搜索的内容很容易使用二进制数来构建(和解释)。
二进制字中的每个位置都应指示是否附加了数组中的某个单词。
让我们假设,你有一个由两个单词组成的数组:
$words = ["foo","bar"];
您现在正在等待组合
foo
bar
bar_foo
以二进制表示,可以表示为
1 0
0 1
1 1
使用三个单词$words = ["foo","bar", "baz"];
,这将是组合
foo
bar
baz
foo_bar
foo_baz
bar_baz
foo_bar_baz
可以解释为
1 0 0
0 1 0
0 0 1
1 1 0
1 0 1
0 1 1
1 1 1
(忽略截至目前的字母排序)
让我们将这些二进制数转换为具体的顺序并查看它们的十进制值:
0 0 1 // dec 1
0 1 0 // dec 2
0 1 1 // dec 3
1 0 0 // dec 4
1 0 1 // dec 5
1 1 0 // dec 6
1 1 1 // dec 7
要注意:您要生成的元素数量为(2^n)-1
,其中n是您的字数。
基本上你需要做的就是:
1
到(2^n)-1
迭代。PHP:
print_r(get_combinations("car bar add"));
function get_combinations($str) {
$words = explode(' ',$str);
$elements = pow(2, count($words))-1;
$result = array();
for ($i = 1; $i<=$elements; $i++){
$bin = decbin($i);
$padded_bin = str_pad($bin, count($words), "0", STR_PAD_LEFT);
$res = array();
for ($k=0; $k<count($words); $k++){
//append element, if binary position says "1";
if ($padded_bin[$k]==1){
$res[] = $words[$k];
}
}
sort($res);
$result[] = implode("_", $res);
}
sort($result);
return $result;
}
结果:
Array
(
[0] => add
[1] => bar
[2] => bar_add
[3] => car
[4] => car_add
[5] => car_bar
[6] => car_bar_add
)
您可以按照字母顺序对数组$res
进行排序。
仅限于3
长度:
print_r(get_combinations("car bar add"));
function get_combinations($str) {
$words = explode(' ',$str);
$elements = pow(2, count($words))-1;
$result = array();
for ($i = 1; $i<=$elements; $i++){
$bin = decbin($i);
$padded_bin = str_pad($bin, count($words), "0", STR_PAD_LEFT);
$res = array();
for ($k=0; $k<count($words); $k++){
//break, if maximum length is reached.
if (count($res) == 3){
break;
}
//append element, if binary position says "1";
if ($padded_bin[$k]==1){
$res[] = $words[$k];
}
}
sort($res);
//check result array if combination already exists before inserting.
$res_string =implode("_", $res);
if (!in_array($res_string, $result)){
$result[] = $res_string;
}
}
sort($result);
return $result;
}
答案 1 :(得分:1)
如果您使用的是PHP 5.5,则可以使用生成器来消除内存问题。它还可以略微降低整体执行时间。
Generators
15: 256kb, 0.48s
16: 256kb, 0.90s
19: 256kb, 7.76s
Original
15: 5.75mb, 0.49s
16: 17.25mb, 0.99s
19: 86.24mb, 8.58s
根据dognose的功能,你可以替换$ result []赋值来代替$ res。该函数不是遍历整个循环并返回一个巨大的数组,而是逐个遍历它,每次返回(产生)一个元素。
function combo_gen($str)
{
$words = explode(' ',$str);
$elements = pow(2, count($words))-1;
$result = array();
for ($i = 1; $i<=$elements; $i++)
{
$bin = decbin($i);
$padded_bin = str_pad($bin, count($words), "0", STR_PAD_LEFT);
$res = array();
for ($k=0; $k<count($words); $k++){
//append element, if binary position says "1";
if ($padded_bin[$k]==1){
$res[] = $words[$k];
}
}
sort($res);
$res = implode("_", $res);
yield $res;
}
}
foreach(combo_gen('one two three') as $item) {
//stuff
}}
答案 2 :(得分:1)
可能有一个更优雅的解决方案,但我用2个功能做到了。
getCombosOfLength函数给出数组中的每个$ intLength组合。 GetCombos函数只为您想要的每个长度运行GetCombosOfLength。这非常适合生成1-5项的所有组合。如果你为所有25项组合运行它,它会有一些问题。
$a = array("c", "b", "f", "v", "g", "e", "h", "i", "j", "k", "l", "m", "n", "p", "o", "r", "a", "q", "s", "t", "u", "w", "x", "y", "z");
$b = getCombos($a, 5);
print "<pre>\n";
print_r($b);
function getCombos($arrInput, $intMax = null) {
sort($arrInput);
if (is_null($intMax)) $intMax = count($arrInput);
$arrOutput = array();
for ($i = $intMax; $i > 0; $i--) {
$arrReturn = getCombosOfLength($arrInput, $i);
for ($j = 0; $j < count($arrReturn); $j++) $arrOutput[] = $arrReturn[$j];
}
return $arrOutput;
}
function getCombosOfLength($arrInput, $intLength) {
$arrOutput = array();
if ($intLength == 1) {
for ($i = 0; $i < count($arrInput); $i++) $arrOutput[] = array($arrInput[$i]);
return $arrOutput;
}
$arrShift = $arrInput;
while (count($arrShift)) {
$x = array_shift($arrShift);
$arrReturn = getCombosOfLength($arrShift, $intLength - 1);
for ($i = 0; $i < count($arrReturn); $i++) {
array_unshift($arrReturn[$i], $x);
$arrOutput[] = $arrReturn[$i];
}
}
return $arrOutput;
}