3

There is a mapping of characters, like so:

$replacements = array(
 array('a', 'b'), // a => b
 array('a', 'c'), // a => c
 array('b', 'n'),
 array('c', 'x'),
);

And there is an input string, say "cbaa". How can I get all combinations, where at least one character is replaced to one of its substitutes? In this example, "a" can be replaced to both "b" and "c", so strings include:

xbaa
cnaa
xbba
cbca
cbab
cbac
...
xnaa
xnac
...
asked Jul 31, 2011 at 19:43
2
  • 1
    no, this is not homework Commented Jul 31, 2011 at 20:20
  • it should be pretty trivial to customize these answers: stackoverflow.com/questions/2617055/… Commented Jul 31, 2011 at 20:24

4 Answers 4

2

Here is an altered version of the code of Dmitry Tarasov (all credits to him please) which seems to be working properly.

class Combine {
 private static $_result = array();
 public static function run($str, $replacements){
 self::_run($str, $replacements, 0);
 return array_values(array_unique(self::$_result));
 }
 private static function _run($str, $replacements, $start){
 self::$_result[] = $str;
 for($i = $start, $l = strlen($str); $i < $l; $i++){ 
 self::_run($str, $replacements, $i+1); 
 if(isset($replacements[$str[$i]])){
 foreach($replacements[$str[$i]] as $key => $val){
 $str[$i] = $val;
 // call recursion
 self::_run($str, $replacements, $i+1);
 }
 }
 }
 }
}
print_r( Combine::run($str, $replacements) );

The private function was introduced to avoid those heavy array operations to be executed multiple times, while they're not used anywhere but from the root-call.

answered Jul 31, 2011 at 20:45
Sign up to request clarification or add additional context in comments.

Comments

2
$replacements = array(
 array('a', 'b'), // a => b
 array('a', 'c'), // a => c
 array('b', 'n'),
 array('c', 'x'),
);
$str = 'cbaa';
// lets change replacements format
$replacementsSorted = array();
foreach ($replacements as $pair) {
 if (isset($replacementsSorted[$pair[0]])) {
 $replacementsSorted[$pair[0]][] = $pair[1];
 } else {
 $replacementsSorted[$pair[0]] = array($pair[1]);
 }
}
$replacements = $replacementsSorted;
class Combine {
 private static $_result = array();
 static function run($str, $replacements, $start) {
 self::$_result[] = $str;
 $l = strlen($str);
 for ($i = $start; $i < $l; $i++) { 
 if (isset($replacements[$str[$i]])) {
 foreach ($replacements[$str[$i]] as $key => $val) {
 $str[$i] = $val;
 if (in_array($str, self::$_result)) {
 continue;
 }
 // call recursion
 self::run($str, $replacements, $i+1);
 }
 }
 }
 return self::$_result;
 }
}
var_dump( Combine::run($str, $replacements, 0) );
answered Jul 31, 2011 at 20:25

2 Comments

Thanks, Dmitry, but it gives 9 results, 8 of which start with "x", which is wrong. Is it the same to you?
Ok_, yep, you have right. Comment above from Joost fix my code
0
function combi($str, $replac, &$result, $builtstr="", $pos=0) {
 $len = strlen($str);
 if ($pos == $len) {
 if ($builtstr != $str)
 $result[] = $builtstr;
 return;
 }
 $c = $str[$pos];
 $poss = array();
 $poss[] = $c;
 foreach($replac as $v) {
 if ($v[0] == $c)
 $poss[] = $v[1];
 }
 foreach($poss as $k=>$c_repl) {
 combi($str, $replac, $result, $builtstr . $c_repl, $pos+1);
 }
}
$combinations = array();
combi("cbaa", $replacements, $combinations);
answered Jul 31, 2011 at 20:49

Comments

0
<?php
error_reporting(E_ALL | E_STRICT);
$replacements = array(
array('a', 'b'), // a => b
array('a', 'c'), // a => c
array('b', 'n'),
array('c', 'x'),
);
$inputstr = "cbaa";
$hash = array(); // hash map maps originals characters with an array of the original character and the other replacements
foreach ($replacements as $pair) {
 if (!isset($hash[$pair[0]])) { $hash[$pair[0]] = array($pair[0]); }
 $hash[$pair[0]][] = $pair[1];
}
echo "hash:\n";
print_r($hash);
$to_flat = array_map(function($c) use ($hash) { // maps original input string characters to an array of candidates
 return $hash[$c];
}, str_split($inputstr));
echo "to_flat:\n";
print_r($to_flat);
$perms = array_reduce($to_flat, function($akku, $letter_targets){
 $theseperms = array();
 foreach ($akku as $work) { // for each permutation made
 foreach ($letter_targets as $target) { // for each character candidate
 $newakku = $work;
 $newakku .= $target;
 $theseperms[] = $newakku;
 }
 }
 return $theseperms;
}, array(""));
unset($perms[array_search($inputstr, $perms, true)]); //remove cbaa
$perms = array_values($perms); //reset keys
echo "perms:\n";
print_r($perms);
?>

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.