In perl how can I generate all possible combinations of numbers contained in a file?

Viewed 151

I found locally the following perl code that calculates all possible combinations for chars or numbers but you need to provide them using a qw function my @strings = [qw(1 2 3 4 5 6 7 8 9 10 11 12 13)];, and I need to read these numbers (1 2 3 4 5 6 7 8 9 10 11 12 13) from a file and pass them to the @strings array or pass the numbers via Perl line command arguments to the mentioned @strings array.

I've read all info regarding qw() but I didn't find a way to use it when reading a file of Perl line command arguments, so can you give some advice in order to fix this issue?.

The output provided now is:

1 2 3 4 5
1 2 3 4 6
1 2 3 4 7 ...

Code:

use strict;
use warnings;

#my $strings = [qw(AAA BBB CCC DDD EEE)];
#my $strings = [qw(1 2 3 4 5 6 7 8 9 10 11 12 13)];
my @strings = [qw(1 2 3 4 5 6 7 8 9 10 11 12 13)];

sub combine;

print "@$_\n" for combine @strings, 5;

sub combine {

  my ($list, $n) = @_;
  die "Insufficient list members" if $n > @$list;

  return map [$_], @$list if $n <= 1;

  my @comb;

  for (my $i = 0; $i+$n <= @$list; ++$i) {
    my $val  = $list->[$i];
    my @rest = @$list[$i+1..$#$list];
    push @comb, [$val, @$_] for combine \@rest, $n-1;
  }

  return @comb;
}
3 Answers

This piece of code initializes an array of numbers (@numbers) from a file:

use strict;
use warnings;

my $filename = "data.txt";
my @numbers; 

open my $fh, "<", $filename or die "Cannot open $filename";

# Read each line into $line
while( my $line = <$fh> ) {
    # Extract each number present at $line
    while( $line =~ /(\d+)/g ) {
        # If found, add the number to @numbers
        push @numbers, $1;
    }
}

close $fh;

"data.txt" contents maybe something like that:

1 2 3
4
5
6 7 8
9
10 11
12

No matters if you have more than one number in each line. If fact they can be in a single row with a separator (something other than a number, like a white space)

First of all, this isn't right:

my @strings = [qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 )];

That creates an array with a single element, a reference to another array.

You want

my @strings = qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 );
combine \@strings, 5;

or

my $strings = [qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 )];
combine $strings, 5;

qw(...) is equivalent to split ' ', q(...), where q(...) is just '...' with a different delimiter.

This means that

my @strings = qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 );
combine \@strings, 5;

is equivalent to

my @strings = split(' ', ' 1 2 3 4 5 6 7 8 9 10 11 12 13 ');
combine \@strings, 5;

But of course, we don't need to use single-quotes to construct the string we pass to split; we could use pass a string that was created from reading a file.

So, the reading-from-file equivalent of

my @strings = qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 );
combine \@strings, 5;

would be

my $line = <>;
chomp($line);
my @strings = split(' ', $line);
combine \@strings, 5;

(The chomp isn't actually necessary because split ' ' ignores trailing whitespace.)

You can do the same using Algorithm::Combinatorics:

use Algorithm::Combinatorics qw(combinations);
my @data = qw(1 2 3 4 5 6);
say join " ", @$_ for combinations( \@data, 2);

Output:

1 2
1 3
1 4
1 5
1 6
2 3
2 4
2 5
2 6
3 4
3 5
3 6
4 5
4 6
5 6
Related