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

Hi Perl Monks, Happy Thanks giving. I am interested in getting the array of People residing in US, @ValidLocations. Banging my head and at last given up. Can you please help me with the following code.

#!/usr/bin/perl use strict; use warnings; my @ValidLocations = ('Lynnwood','Edmonds'); my $ref = { 'US/Seattle/WA' => ['Smith','Eric','Sam'], 'US/WA/Lynnwood' => ['John','Chuck','Ram','Lynda'], 'US/WA/Everette' => ['Sun','Rick','Raj'], 'US/Edmonds/WA' => ['Ken','Josh','Matt'], 'IN/Banglore/KA' => ['Anil','Dada','Kaka'] }; my @keys = keys %{$ref}; foreach my $loc (@ValidLocations) { foreach my $k(@keys){ if (($k =~ /US/) && ($k =~ /$loc/)) { print "@{$ref->{$k}} \n"; } } }

Replies are listed 'Best First'.
Re: iterating 2 arrays
by Athanasius (Archbishop) on Nov 29, 2013 at 03:00 UTC

    I agree with GrandFather that changing $ref (a reference to an anonymous hash) to %hash (an ordinary hash) is the better approach here. But, for completeness, I will point out that the original design can be made to work by changing the line print "@{$ref{$k}} \n; to print "@{$ref->{$k}} \n"; — that is, by adding in the dereferencing operator ->. See perlreftut.

    However, my major concern is with the regular expressions. As written, the first expression $k =~ /US/ will match the character sequence “US” anywhere in the string. It is always a good idea to prevent unwanted matches by limiting, as much as possible, the conditions under which the regex can match. For example:

    if (($k =~ /^US/) && ($k =~ m{/$loc})) {

    might be a useful step in this direction. It matches “US” only at the beginning of the string, and “Lynnwood”, “Edmonds”, etc. only when they follow a forward slash.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: iterating 2 arrays
by GrandFather (Saint) on Nov 29, 2013 at 02:34 UTC

    It's conventional and helpful for you to describe the error or problem. In this case it's evident enough, especially as leaping straight into using a hash reference instead of a hash is something of a code smell.

    Change my $ref = { to my %hash = ( (and change the closing '}' of course). Remove @keys and change my $k(@keys) to my $k (keys %hash).

    True laziness is hard work
      Thanks guys, I updated the existing code, its working now. Culprit was, I was using $ref{$k} instead of $ref->{$k} So dumb :-)

        Please do not just change your OP without indicating (in your OP) what you've changed.

        How to handle this situation is described in "How do I change/delete my post?" (which explains why as well as how).

        Update: While I indicated "OP" above (as that was applicable to this specific case), the information about changing the content of your post applies to any node you write.

        -- Ken

        Culprit was, I was using $ref{$k} instead of $ref->{$k}

        Nope. Unless there is more context than you are telling us, the culprit is using a hash reference instead of a hash.

        References are fine where they are needed, but require needless extra syntax where a simple variable will suffice.

        True laziness is hard work
Re: iterating 2 arrays
by kcott (Archbishop) on Nov 29, 2013 at 04:51 UTC

    G'day sunil9009,

    Another issue you have here is that you're checking all the keys for a match with the first element of @ValidLocations, then checking all the keys again for a match with the next element of @ValidLocations. This means you're performing a lot of unnecessary processing: assuming the data you've posted is just a sample of the real dataset, this could be a substantial amount of unnecessary processing.

    Consider coding your solution more like this:

    #!/usr/bin/env perl -l use strict; use warnings; my @ValidLocations = ('Lynnwood','Edmonds'); my $ref = { 'US/Seattle/WA' => ['Smith','Eric','Sam'], 'US/WA/Lynnwood' => ['John','Chuck','Ram','Lynda'], 'US/WA/Everette' => ['Sun','Rick','Raj'], 'US/Edmonds/WA' => ['Ken','Josh','Matt'], 'IN/Banglore/KA' => ['Anil','Dada','Kaka'] }; my $re = '^US.+?(?:' . join('|' => @ValidLocations) . ')'; my @valid_us_people = map { @{$ref->{$_}} } grep { /$re/ } keys %$ref; print "@valid_us_people";

    Output:

    John Chuck Ram Lynda Ken Josh Matt

    You may already have your data as a hashref. If not, and you choose to change $ref to %hash (as suggested by GrandFather in the first reply), just change $ref->{$_} to $hash{$_} and %$ref to %hash.

    -- Ken

Re: iterating 2 arrays
by KurtZ (Friar) on Nov 29, 2013 at 02:56 UTC
    warning says "Reference found where even-sized list expected at line ..."