2011-09-13 60 views
3

我有一組串,每串具有可變數目的由管分離段(|),例如:「展開」的字符串

$string = 'abc|b|ac'; 

與多於一個的字符的每個部分應被擴展爲所有可能的一個字符的組合,進行3段下面的 「算法」 工程奇妙:

$result = array(); 
$string = explode('|', 'abc|b|ac'); 

foreach (str_split($string[0]) as $i) 
{ 
    foreach (str_split($string[1]) as $j) 
    { 
     foreach (str_split($string[2]) as $k) 
     { 
      $result[] = implode('|', array($i, $j, $k)); // more... 
     } 
    } 
} 

print_r($result); 

輸出:

$result = array('a|b|a', 'a|b|c', 'b|b|a', 'b|b|c', 'c|b|a', 'c|b|c'); 

顯然,對於3個以上的段,代碼開始變得非常混亂,因爲我需要添加(並檢查)越來越多的內部循環。我試圖想出一個動態解決方案,但我無法弄清楚如何爲所有細分(單獨和整體)生成正確的組合。我還查看了一些combinatorics源代碼,但我無法將我的段的不同組合組合起來。

我很感激任何人都可以指出我正確的方向。

+0

訂單有多重要?或者你只需​​要生成所有組合即可? – NullUserException

+0

@NullUserException:每個段的順序都很關鍵,只要沒有重複的c生成,每個字符在該段中出現的順序就是不相關的。 –

回答

3

Recursion救援(你可能需要調整有點覆蓋邊緣的情況下,但它的工作原理):

function explodinator($str) { 
    $segments = explode('|', $str); 
    $pieces = array_map('str_split', $segments); 

    return e_helper($pieces); 
} 

function e_helper($pieces) { 

    if (count($pieces) == 1) 
     return $pieces[0]; 

    $first = array_shift($pieces); 
    $subs = e_helper($pieces); 

    foreach($first as $char) { 
     foreach ($subs as $sub) { 
      $result[] = $char . '|' . $sub; 
     } 
    } 

    return $result; 
} 

print_r(explodinator('abc|b|ac')); 

輸出:

Array 
(
    [0] => a|b|a 
    [1] => a|b|c 
    [2] => b|b|a 
    [3] => b|b|c 
    [4] => c|b|a 
    [5] => c|b|c 
) 

由於看到ideone

+0

哈哈,+1僅用於遞歸鏈接。 ;)謝謝,我會在早上深入研究。 –

+0

@stereo好點,固定。 – NullUserException

+0

做得很好,完美無瑕。 Obrigado! =)@stereofrog:很好。 –

1

你可以有兩個數組:替代方案和一個當前計數器

然後,在一個循環中,你增加計數器的「最後一位數字」,如果等於該位置的替代品的數量,你重置「數字」零和遞增「數字「留給它。這就像用十進制數來計算一樣。

每個步驟的字符串是通過爲每個數字連接$alternatives[$i][$counter[$i]]而構建的。

當「第一位數」變成與該位數的替代數量一樣大時,您就完成了。

例如:對於上述變量,計數器將獲得在步驟以下值:

0,0,0 
0,0,1 
1,0,0 (overflow in the last two digit) 
1,0,1 
2,0,0 (overflow in the last two digits) 
2,0,1 
3,0,0 (finished, since the first "digit" has only 3 alternatives) 
+0

你能舉一個有效的例子嗎?這讓我有點困惑。 – NullUserException

+0

也許這個例子有點幫助。我沒有用PHP寫這個例子,因爲我不太瞭解這種語言。 –

+0

@Roland你可以用其他語言顯示 – tttony

2

這看起來像遞歸編程工作! :P 我首先看了這個,並認爲它將成爲一個在線內容(可能在perl中)。 還有其他非遞歸方式(例如,枚舉索引的所有組合,然後循環遍歷),但我認爲這更有趣,可能更好。

$str = explode('|', 'abc|b|ac'); 
$strlen = count($str); 
$results = array(); 

function splitAndForeach($bchar , $oldindex, $tempthread) { 
    global $strlen, $str, $results; 
    $temp = $tempthread; 
    $newindex = $oldindex + 1; 

    if ($bchar != '') { array_push($temp, $bchar); } 

    if ($newindex <= $strlen){ 
     print "starting foreach loop on string '".$str[$newindex-1]."' \n"; 

     foreach(str_split($str[$newindex - 1]) as $c) { 
      print "Going into next depth ($newindex) of recursion on char $c \n"; 
      splitAndForeach($c , $newindex, $temp); 
     } 

    } else { 

     $found = implode('|', $temp); 
     print "Array length (max recursion depth) reached, result: $found \n"; 

     array_push($results, $found); 
     $temp = $tempthread; 
     $index = 0; 
     print "***************** Reset index to 0 *****************\n\n"; 
    } 
} 

splitAndForeach('', 0, array()); 
print "your results: \n"; 
print_r($results); 
+0

該死的,當我開始寫作的時候,這是沒有答案的,但是我在完成之前就離開了,並且檢查了電子郵件!哦,希望它有助於澄清事情(它可能看起來更小,更整潔,但我認爲有表現力有助於展示)。 – sillyMunky

+0

請參閱NullUserException的答案。 Mine是OP想要遞歸處理的代碼塊的一個相當'純粹'的版本,但是這比他的回答中的代碼效率更低(我定時在控制檯上用更大的字符串運行)。如果速度很重要,使用他的,如果可讀性/定製更重要,我的代碼是有道理的,那就使用它。 – sillyMunky