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

I'm trying to splice out a value from an array that is also in a hash, and I keep getting, 'Global symbol "@array of lists" requires explicit package name...' I hate having to ask for help, but I've been reading and racking my brain for 2 days... Any help would be very appreciated.
my %array_of_lists = ('1' => \@list3, '2' => \@list4, '3' => \@list899 +); #my @array_of_lists = (@list3, @list4, @list899); ##Set my hand my $my_pocket = "AcAs"; #printf("\n\n@array_of_lists\n\n"); #My cards my $my_card1 = substr($my_pocket, 0, 2); my $my_card2 = substr($my_pocket, 2, 2); printf("$my_pocket"); #for (my $z = 0; $z <= 100; $z++ #{ for my $a ( 0 .. scalar(keys %array_of_lists)) { #The loop will iterate through each element (hand of current h +andlist) of the current row and remove any #hand that contains the cards assigned randomly above. for my $b ( 0 .. $#{$array_of_lists->{$b}} ) { #If the first card of the random hand above equal the firs +t card in the element I am currently on, then remove the element from + this handlist by #splicing it out. Or if the first card of the random hand +above equal the second card of the element (hand) I am currently spli +ce it out. if (substr($my_pocket, 0, 2) eq substr($array_of_lists->{$ +a}{$b}, 0, 2) || substr($my_pocket, 0, 2) eq substr($array_of_lists-> +{$a}{$b}, 2, 2)) { $array_of_lists->{$a} = splice(@{$array_of_lists{$a}}, + $b, 1); } elsif (substr($my_pocket, 2, 2) eq substr($array_of_lists- +>{$a}{$b}, 0, 2) || substr($my_pocket, 2, 2) eq substr($array_of_list +s->{$a}{$b}, 2, 2)) { $array_of_lists->{$a} = splice(@{$array_of_lists{$a}}, + $b, 1); } } }

Replies are listed 'Best First'.
Re: working with hashes of arrays
by kyle (Abbot) on Dec 01, 2008 at 22:46 UTC

    First, $a and $b are special variables, and you shouldn't ever name your variables with those names. Never ever.

    Second, this line has a couple of problems:

    for my $b ( 0 .. $#{$array_of_lists->{$b}} )

    You're using $b on the same line where it's declared with my, and you're using $array_of_lists as a hash reference, when you mean to use the %array_of_lists hash. I think what you mean is "$#{ $array_of_lists{$a} }" but again, rename $a and $b. Even at that, your %array_of_lists keys start at 1, so you really want this:

    for my $b ( 1 .. scalar @{$array_of_lists{$a}} )

    There are other places you're misusing %array_of_lists, but I won't mention them all. This should get you on the right track.

    You might also want to look at perlreftut, perlref, and References quick reference.

      Ok, cleaned it up alot, and the only error I'm getting now is: "Can't use string ("AdAh") as ARRAY ref while "strict refs" in use. Also, "AdAh" is coming from the first element in array @list3. So, I have it narrowed down to this statement the below statment. Also, can I splice out elements from the arrays on the fly (without having any problems). Thanks in advance. if (substr($my_pocket, 0, 2) eq substr($array_of_lists{$key}[$t], 0, 2)) Code:
      my %array_of_lists = ('0' => [@list3], '1' => [@list4], '2' => [@list8 +99]); #my @array_of_lists = (@list3, @list4, @list899); ##Set my hand my $my_pocket = 'AcAd'; my ($key, $t); for $key ( 0 .. scalar(keys %array_of_lists)) { #The loop will iterate through each element (hand of current h +andlist) of the current row and remove any #hand that contains the cards assigned randomly above. for $t ( 0 .. scalar @{$array_of_lists{$key}} ) { #If the first card of the random hand above equal the firs +t card in the element I am currently on, then remove the element from + this handlist by #splicing it out. Or if the first card of the random hand +above equal the second card of the element (hand) I am currently spli +ce it out. if (substr($my_pocket, 0, 2) eq substr($array_of_lists{$ke +y}[$t], 0, 2)) { $array_of_lists{$key} = splice(@{$array_of_lists{$key} +}, $t, 1); } elsif (substr($my_pocket, 0, 2) eq substr($array_of_lists{ +$key}[$t], 2, 2)) { $array_of_lists{$key} = splice(@{$array_of_lists{$key} +}, $t, 1); } elsif (substr($my_pocket, 2, 2) eq substr($array_of_lists{ +$key}[$t], 0, 2)) { $array_of_lists{$key} = splice(@{$array_of_lists{$key} +}, $t, 1); } elsif (substr($my_pocket, 2, 2) eq substr($array_of_lists{ +$key}[$t], 2, 2)) { $array_of_lists{$key} = splice(@{$array_of_lists{$key} +}, $t, 1); } } }
        The error report you are getting (Can't use string ("AdAh") as ARRAY ref while "strict refs" in use) is happening because one of these assignment statements:
        $array_of_lists{$key} = splice(@{$array_of_lists{$key}}, $t, 1);
        is replacing the original array_ref value of the hash element with a scalar value -- in other words, where $array_of_lists{$key} was originally initialized as a reference to an array, the statement above is assigning a scalar value to that hash element (the last array value returned by splice, which in this case happens to be the only array value returned by splice). Then, in a later iteration of one of those for loops, you are trying to use that hash element as if it were still a reference to an array (but it isn't anymore).

        If you wanted that assignment to preserve the hash value as an array ref, you would have to do it like this:

        @{$hash_of_arrays{$key}} = splice( ... );

        There are other problems with this version of your code, involving the for loops. Instead of this:

        my ($key, $t); for $key ( 0 .. scalar(keys %array_of_lists)) { for $t ( 0 .. scalar @{$array_of_lists{$key}} ) {
        You should be doing something like this:
        for my $key ( sort {$a<=>$b} keys %hash_of_lists ) { for my $t ( 0 .. $#{$hash_of_lists{$key}} ) {
        where the "$#" sigil represents the index number of the last element in the array (i.e. "$#array" or "$#{$array_ref}" or "$#{$hash_of_arefs{$key}}"). Note that your version of the for loops will both do one iteration too many (and the outer loop wouldn't work at all if the hash keys were not integers that increment from 0).

        Note also the use of sort for ordering the hash keys; that usage of $a and $b (globals that are always declared by perl) is the reason why you don't use those variable names for other things.

        The commentary in your code is not at all clear -- I have no idea what you are really trying to accomplish -- so I can't tell whether your use of splice is appropriate. (I don't use splice much, because I usually find simpler and clearer ways of reducing arrays -- IMHO, splice is a relatively complicated tool, tending to make its users more prone to mistakes that may be hard to debug. The suggestion below from GrandFather about using grep is a good one.)

        Another point to learn from GrandFather's reply: post a self-contained piece of code that other monks can actually run, without having to make up input data on their own. It really helps to have a clear idea about what sort of data you are trying to handle.

        Last nit-pick about improving the comments: since the terms you are using for your variable names are vague, your comments should specifically refer to particular variable names when describing what they contain and how they interact in the code. And/or you could try using variable names that are more clearly descriptive of what they are for. A step-wise synopsis of the overall procedure/goal of the script would also be helpful -- POD is good for that -- if you can't describe this clearly, how could you expect to write code for it?

Re: working with hashes of arrays
by GrandFather (Saint) on Dec 02, 2008 at 02:08 UTC

    If I understand what you are trying to do correctly then an array is the appropriate data structure. Consider:

    use strict; use warnings; my @hand3 = qw/KsQs Js0s/; my @hand4 = qw/AsKc 2s3s/; my @hand899 = qw/1s3c/; my @handsLists = (\@hand3, \@hand4, \@hand899); ##Set my hand my $my_pocket = "AcAs"; #My cards my %pocketCards = map {$_ => 0} $my_pocket =~ /(.{2})/g; printf join '', keys %pocketCards, "\n\n"; for my $hands (@handsLists) { # If either pocket card matches the first hand card omit the hand @$hands = grep {! exists $pocketCards{substr ($_, 0, 2)}} @$hands; print "@$hands\n"; }

    Prints:

    AsAc KsQs Js0s 2s3s 1s3c

    Note the use of grep with a hash to check the first card in each hand in the list against the pocket cards which tidies the code up something wonderful.

    Note too that the variables describe what they contain rather than what manner of data structure they are - that makes understanding what's going on much easier. The context and syntax tell you what the data structure is, but something else has to tell you what the data is.


    Perl's payment curve coincides with its learning curve.
      Grandfather, I can't thank you enough, that is awesome. I can't tell you how much I owe you. Thanks, gman
        How do I do it with both cards?
Re: working with hashes of arrays
by kennethk (Abbot) on Dec 01, 2008 at 22:44 UTC

    Rather than 'Global symbol "@array of lists" requires explicit package name...' I get the error 'Global symbol "$array_of_lists" requires explicit package name...'. When you reference the index in your loops, you are referencing it as a reference to a hash and not the hash itself. (ie $var->{$a} for a reference, $var{$a} for a hash). There was also an index typo fixed below. On the other hand, when selecting an array element, use [] instead of {}.

    Update

    my %array_of_lists = (1 => \@list3, 2 => \@list4, 3 => \@list899); #my @array_of_lists = (@list3, @list4, @list899); ##Set my hand my $my_pocket = "AcAs"; #printf("\n\n@array_of_lists\n\n"); #My cards my $my_card1 = substr($my_pocket, 0, 2); my $my_card2 = substr($my_pocket, 2, 2); printf("$my_pocket"); #for (my $z = 0; $z <= 100; $z++ #{ for my $a ( 0 .. scalar(keys %array_of_lists)) { #The loop will iterate through each element (hand of current h +andlist) of the current row and remove any #hand that contains the cards assigned randomly above. for my $b ( 0 .. $#{$array_of_lists{$a}} ) { #If the first card of the random hand above equal the firs +t card in the element I am currently on, then remove the element from + this handlist by #splicing it out. Or if the first card of the random hand +above equal the second card of the element (hand) I am currently spli +ce it out. if (substr($my_pocket, 0, 2) eq substr($array_of_lists{$a} +[$b], 0, 2) || substr($my_pocket, 0, 2) eq substr($array_of_lists{$a} +[$b], 2, 2)) { $array_of_lists{$a} = splice(@{$array_of_lists{$a}}, $ +b, 1); } elsif (substr($my_pocket, 2, 2) eq substr($array_of_lists{ +$a}[$b], 0, 2) || substr($my_pocket, 2, 2) eq substr($array_of_lists{ +$a}[$b], 2, 2)) { $array_of_lists{$a} = splice(@{$array_of_lists{$a}}, $ +b, 1); } } }
      Could you give me an example? I'm braindead. I thought I could do this with just arrays., but I had to rewrite it. Thanks in advance buddy.
        my %hash = (1 => 'one', 2 => 'two', 9 => 'nine, ); my $hash_ref = \%hash; my @array = values %hash; print $hash{1}; print $hash_ref->{2}; print $array[3];
Re: working with hashes of arrays
by gman1983 (Novice) on Dec 02, 2008 at 04:35 UTC
    Sorry, if they're not clear I want to remove an element from the hash of arrays, which is a 2 card poker hand. Then reset the hash to what it would equal with the hand we got rid of taken out. I need to be able to use the hash later.