Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Help understand why this grep does not work

by drmrgd (Beadle)
on Nov 02, 2013 at 15:32 UTC ( #1060944=perlquestion: print w/ replies, xml ) Need Help??
drmrgd has asked for the wisdom of the Perl Monks concerning the following question:

Just playing around a bit with some text and grep and running into a problem I can't understand. Hoping one of you can enlighten me to what I'm overlooking.

Given two arrays with elements that consist of 3 space delimited characters, I want to print out any elements from array two for which the first two characters match an element from array 1. If I use grep in a scalar context, I can get it to work:

my @data1 = ( "a 1 a", "a 2 T", "a 3 C" ); my @data2 = ( "a 2 Y", "a 3 R", "a 4 Q", "b 5 R" ); for ( @data2 ) { my ($match) = $_ =~ /^(\w\s+\d)/; if ( grep { /$match/ } @data1 ) { print "$_\n"; } }
This correctly prints the result:
$ perl compare.pl a 2 Y a 3 R

However, if I try to use grep in a list context, storing the matches in '@result', I only get the second match and not the first:

my @results; for my $elem ( @data1 ) { my ($match) = $elem =~ /(\w\s+\d)/; @results = grep { /$match/ } @data2; } print "$_\n" for @results;
$ perl compare.pl a 3 R

What am I missing here? Why are both matches not being stored in @results?

Comment on Help understand why this grep does not work
Select or Download Code
Re: Help understand why this grep does not work
by LanX (Canon) on Nov 02, 2013 at 15:42 UTC
    you are overwriting @results in each loop and are only getting the last hits.

    edit

    better try something like push @results, grep {/$match/} @data2;

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: Help understand why this grep does not work
by choroba (Abbot) on Nov 02, 2013 at 15:42 UTC
    You are overwriting @results:
    @results = grep { /$match/ } @data2;

    To add a new value (or values) to an array, use push:

    push @results, grep { /$match/ } @data2;
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Help understand why this grep does not work
by drmrgd (Beadle) on Nov 02, 2013 at 15:47 UTC
    Oh my! What a dumb mistake! Thank you both for pointing that out. I can't believe I missed something so obvious!
      if speed matters you should better consider something like building a hash for array2 for simple lookups or at least a complex OR-ed regex looping just once over array2.

      edit
      DB<102> @data1 = ( "a 1 a", "a 2 T", "a 3 C" ); => ("a 1 a", "a 2 T", "a 3 C") DB<103> @data2 = ( "a 2 Y", "a 3 R", "a 4 Q", "b 5 R" ); => ("a 2 Y", "a 3 R", "a 4 Q", "b 5 R") DB<104> $regex = join "|" , map {/^(\w\s+\d)/} @data1 => "a 1|a 2|a 3" DB<105> grep { /^($regex)/ } @data2 => ("a 2 Y", "a 3 R")

      think I spotted (and corrected) a bug in your logic, you forgot to anchor to string start '^' in your grep regex.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        I wondered about building a hash for this. What would be the best way? Are you thinking something like this is better:
        my %data_hash = map { /(\w\s+\d)/ => $_ } @data2; for my $key ( %data_hash ) { print "$data_hash{$key}\n" if grep { /^$key/ } @data1; }

        I also wondered about anchoring that match. In earlier versions, I did anchor it. But, I wasn't sure if it was necessary given the data set. I think I'll add it back as it's probably safer.

        Thanks for the advice!

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1060944]
Approved by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (6)
As of 2014-07-30 06:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (229 votes), past polls