Beefy Boxes and Bandwidth Generously Provided by pair Networks RobOMonk
Perl Monk, Perl Meditation
 
PerlMonks  

Trouble grepping values when hash contains multiple values per key

by dirtdog (Beadle)
on Jun 05, 2010 at 15:35 UTC ( #843273=perlquestion: print w/ replies, xml ) Need Help??
dirtdog has asked for the wisdom of the Perl Monks concerning the following question:

Ye Wise ones, i'm struggling over here...would love ye help.

I'm going to show you an example using one file format that works followed by an example with a new file format that does not work..And due to a requirements change i need to use the one that's not working

This is an example where the grep works when i use a manually created holiday file:

In this case $hol_file contains holidays for all global exchanges..below is the file format which i manually created (small sample of it):

CA: 20100101 20100215 20100305

US: 20100101 20100528 20100101

JP: 20100305 20100527 20100322

open CONFIG, "$hol_file" || die "Cannot open log for writing. $!"; while(<CONFIG>) { next if /^\s*$/ || /^\#/; chomp; if(/([^:\s]+):\s+(.*)/) { push @{$countries{$1}}, "$2"; } }

##$cntry_of_issue is a 2 char Country Code derived For purposes of this example let's assume it's US

my $date = 20100101; my @date = grep /$date/,@{$countries${cntry_of_issue}})

That worked splendidly but the global cal was too manually intensive. Now I'm receiving a new comma delimited global calendar file and am trying to do something similar to above, but the grep is not working (it's not finding the matching date).

The following example does NOT work:

$hol_file is now the new comma delimited file below (small sample of it):

978,XBRN,CH,Berne Stock Exchange,2010,20100101

978,XBRN,CH,Berne Stock Exchange,2010,20100102

978,XBRN,CH,Berne Stock Exchange,2010,20100321

978,XBRN,CH,Berne Stock Exchange,2010,20100324

open CONFIG, "$hol_file" || die "Cannot open log for writing. $!"; while (<CONFIG>) { chomp; next if /^\s*$/ || /^\#/; my $aref = [split /,/, $_]; push( @{$countries{$aref->[2]}}, $aref->[5]); }

##$cntry_of_issue is a 2 char Country Code derived For purposes of this example let's assume it's CH

my $date = 20100101; my @date = grep /$date/,@{$countries${cntry_of_issue}})

The grep in this case does NOT find the $date. Is it because the values(holidays) of the key (country), in this case "CH", is not a true list like in the 1st example above?

ur help for a solution is very much appreciated! Thanks

Comment on Trouble grepping values when hash contains multiple values per key
Select or Download Code
Re: Trouble grepping values when hash contains multiple values per key
by toolic (Chancellor) on Jun 05, 2010 at 15:53 UTC
    my @date = grep /$date/,@{$countries${cntry_of_issue}})
    That code doesn't even compile. Try this instead:
    my @dates = grep /$date/, @{ $countries{$cntry_of_issue} };

    I got rid of the unmatched right paren, added a semicolon, and moved the dollar sign to the right of the curly bracket to form the scalar variable $cntry_of_issue, rather than the bareword cntry_of_issue.

    Here is a self-contained example which seems to work for me:

    use warnings; use strict; use Data::Dumper; my %countries; while (<DATA>) { chomp; next if /^\s*$/ || /^\#/; my $aref = [split /,/, $_]; push( @{$countries{$aref->[2]}}, $aref->[5]); } my $date = 20100101; my $cntry_of_issue = 'CH'; my @dates = grep /$date/, @{ $countries{$cntry_of_issue} }; print Dumper(\@dates); __DATA__ 978,XBRN,CH,Berne Stock Exchange,2010,20100101 978,XBRN,CH,Berne Stock Exchange,2010,20100102 978,XBRN,CH,Berne Stock Exchange,2010,20100321 978,XBRN,CH,Berne Stock Exchange,2010,20100324
    Prints:
    $VAR1 = [ '20100101' ];

      Thanks Toolic

      When i pasted the code in, some of the syntax got messed up, specifically the curly braces, but i did have the same syntax that you had

      I ran what you had and it did work beautifully

      ultimately, i'm trying to get the following piece of code to work. Basically, I have my date and i check it against the calendar file to see if the date is a holiday...if it does exist it means it's a holiday so i increment the date by 1 day (unless it's a sat or sun..then i increment it until it's not sat or sun..this piece of logic works), then i check the newly incremented date against the holiday file again. I repeat this until it doesn't exist in the holiday file. Then i know i have a date that's not a holiday.

      The following code for some reason is not working for me. It's hitting the until loop but not entering it even if the newly incremented date is also a date in the holiday file

      You may need to mock up the holiday config file with back to back holiday's to create the scenario

      $date='20100101'; $new_date=get_next_bus_day($date);
      until (my @date = grep !/$new_date/,@{$countries${cntry_of_issue}}) { $new_date=get_next_bus_day($new_date); }
      sub get_next_bus_day { my $inc=1; my $inc4sat=2; my $inc4fri=3; my $new_date; my $date=shift; DEBUG > 1 and print "date is: >$date<\n"; my $y = substr($date,0,4); my $m = substr($date,4,2); my $d = substr($date,6,2); my $time = timelocal("", "", "", $d, $m-1, $y); if ((localtime($time))[6] == 5) { $new_date=strftime "%Y%m%d", localtime timelocal(0,0,0,$d,$m-1,$y) + +($inc4fri * 24 * 60 * 60); } elsif ((localtime($time))[6] == 6) { $new_date=strftime "%Y%m%d", localtime timelocal(0,0,0,$d,$m-1,$y) + +($inc4sat * 24 * 60 * 60); } else { $new_date=strftime "%Y%m%d", localtime timelocal(0,0,0,$d,$m-1,$y) + +($inc * 24 * 60 * 60); } return $new_date; }

      Do you see any obvious reason why this wouldn't work?

      I see the problem now

      I'm expecting grep to return true or false, but since this is a list context it will return the actual values. Is there any way to force grep to evaluate these in a scalar context in order to return a "true" or "false" in this case?

        Is there any way to force grep to evaluate these in a scalar context in order to return a "true" or "false" in this case?
        Something like:
        my @date = grep ... if (@date) { ... }

        I just changed the until loop to a while loop and now it's working as expected

        Sorry for wasting your time...I was not thinking clearly

        while (my @date = grep /$new_ex_date/,@{$countries{$cntry_of_issue}}) { $new_date=get_next_bus_day($new_date); }
        Is there any way to force grep to evaluate these in a scalar context in order to return a "true" or "false" in this case?

        Yes, evaluate grep in scalar context. It's that easy!

        my $found_any = grep { ... } @whatever;

        Boolean context is also a scalar context.

Re: Trouble grepping values when hash contains multiple values per key
by NetWallah (Monsignor) on Jun 05, 2010 at 16:22 UTC
    The other hidden problem in your code is the construct:
    open CONFIG, "$hol_file" || die "Cannot open log for writing. $!";
    This will fail silently, because of operator precedence. Use "or" instead of "||".

    Best practices say you should use the 3-parameter form of "open", and local file handles, so your code should read:

    open (my $config , "<", "$hol_file") or die "Cannot open '$hol_file': +$!";

         Syntactic sugar causes cancer of the semicolon.        --Alan Perlis

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (8)
As of 2014-04-21 09:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (492 votes), past polls