views:

105

answers:

3

Question: Why can't I push elements into a 2d array that's inside of a while loop that parses through a SQL result set?

I need some help here as to why this happens. The way data is stored into a 2d array can be done several ways, but for my purposes, I need to use the push method.

Here's some code that works:

my @tt = (0,1,2,3);
my @t;
push (@t,\@tt);
print "[0][0]:".$t[0][0]."\n";
print "[0][1]:".$t[0][1]."\n";
print "[0][2]:".$t[0][2]."\n";
print "[0][3]:".$t[0][3]."\n";
@tt = (4,5,6,7);
push (@t,\@tt);
print "[1][0]:".$t[1][0]."\n";
print "[1][1]:".$t[1][1]."\n";
print "[1][2]:".$t[1][2]."\n";
print "[1][3]:".$t[1][3]."\n";

The output is:

-------------------------
[0][0]:0
[0][1]:1
[0][2]:2
[0][3]:3
[1][0]:4
[1][1]:5
[1][2]:6
[1][3]:7


Here's the problem I'm having

I'm running some SQL to build up a result set with X number of columns. To store the data into my array, I figured I could use the same syntax as above:

while (@results=$sth->fetchrow_array())
{
    push(@stu_pool,\@results);
} 

I tested the SQL and checked the result set, so the problem is not related to that. I have also reverted back to the long-hand approach which leaves me with my desired end result. Instead of using push(@stu_pool,\@results); I used this code inside the loop:

$stu_pool[$index][0] = $results[0];
$stu_pool[$index][1] = $results[1];
$stu_pool[$index][2] = $results[2];
$stu_pool[$index][3] = $results[3];
$stu_pool[$index][4] = $results[4];
$stu_pool[$index][5] = $results[5];
$stu_pool[$index][6] = $results[6];
$index++;

So what is preventing me from pushing elements into this array? It works fine with the first example, but when I try to print out the elements, they are all blank. The code I'm using:

print "[0][0]:".$stu_pool[0][0]."\n";
print "[0][1]:".$stu_pool[0][1]."\n";
print "[0][2]:".$stu_pool[0][2]."\n";
print "[0][3]:".$stu_pool[0][3]."\n";
print "[1][0]:".$stu_pool[1][0]."\n";
print "[1][1]:".$stu_pool[1][1]."\n";
print "[1][2]:".$stu_pool[1][2]."\n";
print "[1][3]:".$stu_pool[1][3]."\n";

To repeat:

Why does the push method fail to work inside the while loop?

+5  A: 

There's only one @results -- you're making every element of @stu_pool a reference to the same @results, which (the last time the loop condition is checked) will eventually be set to contain ().

What you want is to add my: while (my @results = $sth->fetchrow_array) { will work just fine, because now each time through the loop, @results is a different array.

hobbs
thanks... I follow that reasoning. My assumption for the behavior of this loop was that the elements of `@results` was being loaded with a single result row's fields and reset itself to the next row's fields on each iteration
CheeseConQueso
@Cheese: that is correct, but the array reference (the actual thing you are storing) is not changed on each iteration. So you're just overwriting last row's results with the next results.
Ether
@ether - I understand now, thanks. Are there any other secrets with regards to this specific area of variable usage/manipulation (for arrays or otherwise) that I should know about? Any good references/guides you know of? I'm teaching myself Perl as I go and get stuck at these intricacies
CheeseConQueso
@Cheese: [perldoc perldata](http:/perldoc.perl.org/perldata.html), [perldoc perldsc](http:/perldoc.perl.org/perldsc.html), [perldoc perlreftut](http:/perldoc.perl.org/perlreftut.html). Also the books *Beginning Perl*, *Intermediate Perl*, *Mastering Perl*.
Ether
+6  A: 

Let me change your first example a bit.

my @tt = (0,1,2,3);
my @t;
push (@t,\@tt);
@tt = (4,5,6,7);
push (@t,\@tt);
print "[0][0]:".$t[0][0]."\n";
print "[0][1]:".$t[0][1]."\n";
print "[0][2]:".$t[0][2]."\n";
print "[0][3]:".$t[0][3]."\n";
print "[1][0]:".$t[1][0]."\n";
print "[1][1]:".$t[1][1]."\n";
print "[1][2]:".$t[1][2]."\n";
print "[1][3]:".$t[1][3]."\n";

Output:

[0][0]:4
[0][1]:5
[0][2]:6
[0][3]:7
[1][0]:4
[1][1]:5
[1][2]:6
[1][3]:7

You're not copying @tt into @t. You're putting a reference to the variable @tt into @t. So when something else happens to @tt, it changes when fetched through @t as well. To really make a copy, you want push(@t,[@tt]) or @{$t[$i]} = @tt if $i is an appropriate index variable.

Or for the other example, try push(@stu_pool, [@results]);

aschepler
thanks for the clarification - I wasn't aware of what the `\` did. I picked it up from an example I saw online when I was trying to find out how to do 2d arrays in Perl - also, thanks for the last line in your post. that's what I was really looking for
CheeseConQueso
Could I also have used some combination of a foreach(@results) and the `$_` variable to get the same effect?
CheeseConQueso
@CheeseConQueso: I'm not entirely sure what you mean there, but I suspect the answer is "yes, but why introduce another loop when you don't need to?"
aschepler
CheeseConQueso
Well, that only calls `fetchrow_array` once. And careful: `@_` is not `$_`. Have you read perldoc perllol? [http://perldoc.perl.org/perllol.html ]
aschepler
Actually, now that I look at them again, I recommend reading perlreftut [ perldoc.perl.org/perlreftut.html ] before perllol.
aschepler
thanks - you're at 1k now too
CheeseConQueso
A: 

Why loop at all? It's much easier to do:

my $results = $sth->fetchall_arrayref();

or if you insist on using an array variable:

my @results = @{$sth->fetchall_arrayref()};
mscha
" Can't locate object method "fetchall_arrayref" via package "sth" (perhaps you forgot to load "sth"?) "
CheeseConQueso
That’s because he made the trivial mistake of leaving out the `$` sigil on `$sth`. I fixed it.
Aristotle Pagaltzis
Oops, sorry... Thanks for fixing.
mscha