Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
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 lurking in the Monastery: (11)
As of 2014-09-19 14:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (140 votes), past polls