drug_user841417
drug_user841417

Reputation: 827

Perl - Create a brute force list

New to Perl, I'm trying to define a subset of characters and then output all possible combinations (max 8 characters) of them in a text file.

I'm really not comfortable with the 'default variable' or other aspects of Perl, so I'm starting with pseudo code in hopes that someone can help me with the specifics (I learn best from examples).

#Define output file
$filename=output.dat
$standard_output->$filename

#Define list
$list[]=regex/a..z 0..9/

#Cycle through iterations
foreach $letter1 in $list{
 print $list[$letter]
}

foreach $letter1 in $list{
 foreach $letter2 in $list{
  print $list[$letter1] $list[$letter2]
 }
}

...

foreach letter1 in list{
 foreach letter2 in list{
  foreach letter3 in list{
   foreach letter4 in list{
    foreach letter5 in list{
     foreach letter6 in list{
      foreach letter7 in list{
       foreach letter8 in list{
        print list[letter1] list[letter2] list[letter3] list[letter4] list[letter5] list[letter6] list[letter7] list[letter8]
       }
      }     
     }
    }
   }
  }
 }
}

As you can clearly see, I'm very new at this. Can someone help me get my bearings with Perl?

Upvotes: 0

Views: 2076

Answers (2)

brian d foy
brian d foy

Reputation: 132863

My Set::CrossProduct module makes this easy, and it does it without stack- or memory-busting recursion:

use v5.10;

use Set::CrossProduct;

my $min = 2;
my $max = 4;
my $set = [ qw( a b 1 2 ) ];

foreach my $length ( $min .. $max ) {
    say "Getting combinations of length $length";

    my $cross = Set::CrossProduct->new(
        [ ( $set ) x $length ]
        );

    while( my $tuple = $cross->get ) {
        say join '', @$tuple;
        }
    }

Upvotes: 4

amon
amon

Reputation: 57640

Functional Programming* to the rescue! The following code won't be too efficient, but far cleaner.

We will define a function that takes a number and a list as arguments. The number denotes how many times we have to recurse, the list holds the letters from the outer levels.

#!/usr/bin/perl
use strict; use warnings;
my @list = 'a' .. 'z'; # lowercase letters
sub combinations {
   my ($recursions, @letters) = @_; # unpack the arguments
   if ($recursions == 0) {
       print @letters, "\n"; # print the letters, append newline
   } else {
      # do a loop
      $recursions--; # reduce level
      for my $letter (@list) {
         combinations($recursions, @letters, $letter);
      }
   }
}

We can call that sub with combinations(8); to get the expected result.

The .. is the range operator and produces a list. It works with alphabetic characters too. You will want 'a' .. 'z', 0 .. 9.

It works, although you might want to use a smaller @list for testing.

This produces all fixed-length strings. To get all strings up to a given length, just do

combinations($length) foreach my $length (1 .. 8);

(breadth-first), or include

print @list, "\n";

just before the for-loop in the else-branch for depth-first.

Footnotes:

(*) No, not really, but this is something close. Functional Programming does not require any loops at all.

Upvotes: 3

Related Questions