BurningBeard has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have a relatively long script, that is an implementation of a combinatorics algorithm I have created for my diploma, and at some point, I generate several maps of the type:
a -> a1
b -> b1
c -> c1
And there is a string that is affected by this replacement - say, "aabc".

Is there any quick and already created way to display all possible results of replacement, like: a1abc, a1ab1c, a1ab1c1, a1abc1, a1a1bc, etc?

I believe, it is possible to manually do this by applying regexes on various substrings, but this way, IMHO, is quite slow.

Replies are listed 'Best First'.
Re: How to show all possible replacements?
by RichardK (Parson) on May 12, 2013 at 14:47 UTC

    Does speed really matter? If you're only going to run this once, then understanding the code is much more important.

    If it's slow in real terms, then you must be processing lots of data, so I assume you'll generate lots of alternative strings. But what are you really looking for ? There may be better ways to solve your underlying problem.

    Anyway, glob is one simple way to get a list of alternatives. The help says :-

    If non-empty braces are the only wildcard characters used in the "glob +", no filenames are matched, but potentially many strings are returned. For example, this produces nine strings, one for each pairing of fruit +s and colors: @many = glob "{apple,tomato,cherry}={green,yellow,red}";
      Thank you for your reply, I'll check glob out.
      I have created an algorithm that processes quite large binary words, to acquire complexity-related characteristics from them, one being the amount of ways to create this word using only concatenation, and in minimal amount of operations used.

      The complete algorithm basically divides the original word into two parts, recursively uses itself to look for easiest ways to concatenate the smallest word(left in case the word was halved on step 1). The concatenation scheme of the smallest word is called later as prehistory of this word - the list of word already created, and those can be used to create the second word.
      The question posted arose, when I started to test this algorithm on larger words, say:
      Word = 01101001, maximum complexity is 5.
      1. A = 01; B = 101001.
      2. P(A) = {0,1;01}, C(A) = 1;
      3. Map generated:
      01 -> a;
      4. If B is replaced only the greediest way possible: 1a0a, it can be created in 3 steps, but, the algorithm misses a scheme, since the word 1010a can also be created in 3 steps, so it also does not break the rule:
      C(A) + C(B) = C(W) + 1
Re: How to show all possible replacements?
by LanX (Saint) on May 12, 2013 at 17:26 UTC
    use glob

    DB<125> @combis = glob("{a,a1}{b,b1}{c,c1}") => ("abc", "abc1", "ab1c", "ab1c1", "a1bc", "a1bc1", "a1b1c", "a1b1c1 +")

    glob takes a string which you can construct by replacing every "a" with "{a,A}" and so on...

    see also Re: Substitution of a particular letter in all combinations of positions in word (see inside)

    Cheers Rolf

    ( addicted to the Perl Programming Language)

    UPDATE

    DB<129> $s = "aabc" => "aabc" DB<130> %r = ( a=>A, b=>B, c=>C ) => ("a", "A", "b", "B", "c", "C") DB<131> $s =~ s/(\w)/{$1,$r{$1}}/g => 4 DB<132> $s => "{a,A}{a,A}{b,B}{c,C}" DB<133> print "$_\n" while glob($s) aabc aabC aaBc aaBC aAbc aAbC aABc aABC Aabc AabC AaBc AaBC AAbc AAbC AABc AABC
Re: How to show all possible replacements?
by hdb (Monsignor) on May 12, 2013 at 18:09 UTC

    Instead of glob you can also use explicit enumeration of all possibilities. There are 2**n of them if n is the length of your word. If you translate all numbers from 0 to 2**n-1 into binary and translate 0 into the empty string, you get all combinations. The following script compares run time against glob.

    use strict; use warnings; use Time::HiRes qw[ time ]; # explicit enumeration my $s = time; my $string = "aabc"; my $n = length $string; my $p = 2**$n; for( my $i=0; $i<$p; $i++ ) { my $x = sprintf( "%0${n}b", $i ); print substr( $string, $_, 1 ), substr( $x, $_, 1) ? "1" : "" for 0. +.$n-1; print "\n"; } print STDERR "time: ", time-$s, "\n"; # using glob $s = time; my $g = ""; $g .= substr( $string, $_, 1 ).'{,1}' for 0..$n-1; print "$_\n" while( glob $g ); print STDERR "time: ", time-$s, "\n";

    On my machine it seems that explicit enumeration is slightly faster but not much.

Re: How to show all possible replacements?
by Athanasius (Archbishop) on May 13, 2013 at 02:00 UTC