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

Dear Monks, I have used map function in my program but it has made my program dead slow :( Can u help me how to replace this function with some other code.
here is my code :-
#!/usr/bin/perl -w $fn=$ARGV[0]; open(FH, $fn) || die "Cannot open file"; while( <FH> ) { chomp($_); $href{$1} = $2 if $_ =~ /(\S+)\s+(\S+)/; } while (my ($key, $value) = each(%href)) { #print $key. ", ". $value."\n"; } close FH; $fh=$ARGV[1]; open(FD, $fh) || die "Cannot open file"; my @input_array = <FD>; foreach my $line (@input_array) { chomp($line); my $cnt = 0; map {($line =~ /$_/)?++$cnt:$cnt}keys %href; print "$cnt $line\n"; } close FD;

Replies are listed 'Best First'.
Re: Map function slowing down program
by ikegami (Patriarch) on Nov 17, 2008 at 01:41 UTC
    You're compiling the same regular expressions over and over again, once for every line in the second file. Note the use of qr// below.
    #!/usr/bin/perl -w use strict; my @regexps; { my $fn = $ARGV[0]; open(my $fh, '<', $fn) or die "Cannot open pattern file \"$fn\": $!\n"; while( <$fh> ) { chomp; my ($pat) = /(\S+)\s+\S+/ or next; push @regexps, qr/$pat/; } } { my $fn = $ARGV[1]; open(my $fh, '<', $fn) or die "Cannot open data file \"$fn\": $!\n"; while ( <$fh> ) { chomp; my $cnt = 0; for my $re (@regexps) { ++$cnt if /$re/; } print "$cnt $_\n"; } }

    Other improvements:

    • Added "use strict;", a tool that will help you find many errors.
    • Since you weren't using the values of the %href, I got rid of it.
    • Switched map for for since you discard the return value returned by map.
    • Changed global variables FH and FD into lexicals.
    • Used safer 3-arg open.
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Map function slowing down program
by jwkrahn (Abbot) on Nov 17, 2008 at 02:22 UTC

    You can use the fact that map returns a value:

    my $cnt = map $line =~ /$_/, keys %href;

      Absolutely! Using map purely for the side-effect of incrementing a counter is a little obtuse. The code is a lot cleaner using the return value of map (or grep).

      That should be grep (I also favor using an array rather than a hash):
      >perl -wMstrict -le "my @strs = qw( ab cd ef gh ); my @rxs = map qr{ \Q$_\E }xms, @strs; my $line = 'xxabyyefzzghhh'; my $cnt = grep $line =~ $_, @rxs; print $cnt; " 3

        It works with map as well as with grep.   Try it and see.

Re: Map function slowing down program
by johngg (Canon) on Nov 17, 2008 at 12:07 UTC

    It looks like you might still be working towards a solution to the problem you posted here. I'd be interested to know if that is the case and, if so, how we can help you further in reaching a solution. I may be wrong and this could be a whole new problem or the original requirements might have evolved.

    Cheers,

    JohnGG