in reply to Hashes and Arrays

First things first... %hash->{"IP"} ... don't use that syntax. It's deprecated. It isn't widely used. It is easily confused with a dereference. Did I mention that it's deprecated? It was only by accident that it worked in the first place. It's long and ugly. Oh, and it is deprecated too. Don't use it. Use $hash{IP} instead. You'll be doing yourself a favor.

Ok, now that that is out of the way, let's rewrite your code a bit. We'll clean up the indenting, combine the declarations and initializations, and remove a little cruft. Let's get rid of your @rows array too; it isn't necessary for this example (all you use it for is to hold the value 'IP'.) We can also get rid of your loop at the end because the example only deals with one key: IP.

my @newrows = qw( value1 value2 ); my @printrows; my %newhash; push @{$newhash{ IP }}, @newrows; push @{$newhash{ IP }}, @newrows; @printrows = $newhash{ IP }; print $printrows[0][0], "\n"; # should be Value1? print $printrows[1][1], "\n"; # should be Value2? print "\n";
There. Now your question becomes a little more clear. It seems you are a little confused about how complex data structures work.

Step by step...

push @{$newhash{ IP }}, @newrows;
After that line is evaluated, $newhash{ IP } holds a reference to an array. The elements of the array are copies of the same two elements that are in @newrows, namely 'value1' and 'value2'.

After you do it again with

push @{$newhash{ IP }}, @newrows;
the array that your reference, $newhash{ IP }, refers to contains 2 copies of the @newrows array. It might be easier to see what you are doing if you remove some complexity. Examine the one-liner perl -le 'my @a = (1, 2); push @b, @a; push @b, @a; print for @b' and its output.

So, that's the mistake you made during construction of your data structure. Now let's take a closer look at how you attempt to use it.

@printrows = $newhash{ IP };
That doesn't do what you expect it to. After that, @printrows has one element: the reference stored in $newhash{ IP }. If you want to copy the array refered to by that reference, then you'd need something like @printrows = @{ $newhash{ IP } }; instead.

Moving on...

print $printrows[0][0], "\n"; # should be Value1?
Indeed, that is 'value1'. Just not for the reasons that you'd like it to be. That only works because of the error you made in the last step. Remember that @printrows holds a single value, a reference. That reference, $printrows[0] is a reference to the array you constructed. The first element in that array, $printrows[0]->[0] which can also be written in short form as $printrows[0][0], is 'value1'.

The next line

print $printrows[1][1], "\n"; # should be Value2?
fails to print 'value2'. Once again, recall that @printrows only has one element. That element is indexed by 0 (where we found it above.) There is no element at index 1, so $printrows[1] evaluates to undef. So does $printrows[1][1] for that matter. However, had you been running with warnings enabled (either with the -w switch to perl or the use warnings pragma), you would have found that this line resulted in the message "use of uninitialized value in print at ..." which might have helped some.

You should probably read some of the tutorials that come with perl like perlreftut, perldsc, perllol. For reference, you should also familiarize yourself with perldata.

Good luck!

-sauoq
"My two cents aren't worth a dime.";

Replies are listed 'Best First'.
Re: Re: Hashes and Arrays
by datannen (Novice) on Jul 16, 2003 at 13:17 UTC
    Thanks for all your help and links. I fixed up my perl coding a bit now. However, I still have the core problem. To iterate through each row, I have to do something like this:
    my $x = 0; while ($printrows[0][$x]) { print "First: $rows[0][$x]\n"; $x++; print "Second: $rows[0][$x]\n"; $x++; }
    I really want to do this for each row:
    my $x = 0; while ($printrows[$x][0]) { print "First: $rows[$x][0]\n"; print "Second: $rows[$x][1]\n"; }
    Because, then I can reference a row directly without having to do: $x=2 X 15, $rows[0]$x to get to the 15th row.

      You should probably forget about using a separate @printrows variable as you are initializing it to contain only one value anyway. Why not just use the original $newhash{ IP }?

      That's supposed to be an array reference anyway.

      I think I might have a handle on what you are trying to do now...

      my %newhash; push @{ $newhash{IP} }, [ 'row 0, col 0', 'row 0, col 1' ]; push @{ $newhash{IP} }, [ 'row 1, col 0', 'row 1, col 1' ]; # $newhash{ IP } contains a reference to an array with two elements. # Each element is itself a reference to an array with two elements. print $newhash{IP}->[0][0], "\n"; # row 0, col 0 print $newhash{IP}->[0][1], "\n"; # row 0, col 1 print $newhash{IP}->[1][0], "\n"; # row 1, col 0 print $newhash{IP}->[1][1], "\n"; # row 1, col 1

      -sauoq
      "My two cents aren't worth a dime.";