views:

364

answers:

3

I'm trying to create an array of hashes, but I'm having trouble looping through the array. I have tried this code, but it does not work:

for  ($i = 0; $i<@pattern; $i++){
  while(($k, $v)= each $pattern[$i]){
    debug(" $k: $v");
  }
}
+6  A: 

Try this instead:

for my $hashref (@pattern) {
    for my $key (keys %$hashref) {
        debug "$key: $hashref->{$key}";
    }
}

The biggest problem with what you were trying was each $pattern[$i]. The each function expects a hash to work on, but $pattern[$i] returns a hashref (i.e. a reference to a hash). You could fix your code by dereferencing $pattern[$i] as a hash:

while(my($k, $v) = each %{$pattern[$i]}) {

Also, beware of the each function, it can leave the hash iterator in an incomplete state.

Chas. Owens
Beat me by 11 seconds. Perhaps I should ramble less.
Chris Lutz
I try to post quickly, then go back and ramble.
Chas. Owens
It is a good strategy. Truly I have much to learn. Also, interesting piece about why `each()` is bad. I like your Star Wars reference.
Chris Lutz
The `each` function isn't so much bad as dangerous. And the `keys` function isn't completely safe either: `my @keys = keys %hash`. What happens if %hash is a tied dbm that holds many times what memory will hold? In this case, `while (my ($key, $val) = each %hash) {}` is clearly superior.
Chas. Owens
+13  A: 

First, why aren't you useing strict and warnings? The following lines should be at the top of every Perl program you create, right after #!/usr/bin/perl. Always.

use strict;
use warnings;

And I know you aren't because I'm pretty sure you'd get some nice error messages out of strict and warnings from this, and from many other places in your code as well, judging by your variable use.

Second, why aren't you doing this:

for my $i (@pattern) {
  ..
}

That loops through every element in @pattern, assigning them to $i one at a time. Then, in your loop, when you want a particular element, just use $i. Changes to $i will be reflected in @pattern, and when the loop exits, $i will fall out of scope, essentially cleaning up after itself.

Third, for the love of Larry Wall, please declare your variables with my to localize them. It's really not that hard, and it makes you a better person, I promise.

Fourth, and last, your array stores references to hashes, not hashes. If they stored hashes, your code would be wrong because hashes start with %, not $. As it is, references (of any kind) are scalar values, and thus start with $. So we need to dereference them to get hashes:

for my $i (@pattern) {
  while(my($k, $v) = each %{$i}) {
    debug(" $k: $v");
  }
}

Or, your way:

for  (my $i = 0; $i<@pattern; $i++) { # added a my() for good measure
  while(my($k, $v) = each %{$pattern[$i]}) {
    debug(" $k: $v");
  }
}
Chris Lutz
I love you ^^. Yes please, use "my"...
Clement Herreman
+1 for the rambling. ;)
ire_and_curses
Haha, thank you for your answer, even if there was a lot to read through to get there :p What I was looking for was the %{$i} (or %{$_} to regain some of my Perl honor).
Marius
For the record, the brackets aren't strictly necessary - you could write `%$i` in this case. The reason I used brackets is that, if you get more complex than just `$i`, you need them: `%{$pattern[$i]}` can't be written as `%$pattern[$i]`, because the second is ambiguous.
Chris Lutz
+3  A: 

See the documentation for the perl data structures cookbook: perldoc perldsc

William Pursell