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

Here's a snippet of the code. What you'll see is that I can print data from my foreach pull, but I'm not able to push it to a multidimensional array:
$qry = $DB->Query("SELECT * FROM recipes WHERE type = '$type' ORDER +BY rand() limit $quantity") || die "Got error on select: $Mysql::db_errstr\n"; + for ($i=0; $i<$qry->numrows; $i++) { @row = $qry->fetchrow or warn "recipes didn't find a matching row" +; print "\@row is assigned @row\n"; $j = 0; foreach my $bug (@row) { @athlete[$i,$j++] = $bug ; print "\$i\$j is assigned $i:$j\n"; print "\@athlete[\$i,\$j] is assigned the value @athlete[$i,$j]\ +n"; print "\$bug is assigned the value $bug\n"; } } }
@row is assigned 33 Small Bunch Grapes carb 15 0.4 0.1 $i$j is assigned 4:1 @athlete[$i,$j] is assigned the value 33 $bug is assigned the value 33 $i$j is assigned 4:2 @athlete[$i,$j] is assigned the value Small Bunch Grapes $bug is assigned the value Small Bunch Grapes $i$j is assigned 4:3 @athlete[$i,$j] is assigned the value carb 0.2 $bug is assigned the value carb $i$j is assigned 4:4 @athlete[$i,$j] is assigned the value 15 15 $bug is assigned the value 15 $i$j is assigned 4:5 @athlete[$i,$j] is assigned the value $bug is assigned the value 0.4 $i$j is assigned 4:6 @athlete[$i,$j] is assigned the value 0.1 $bug is assigned the value 0.1
Particuarly, $bug is able to receive 0.4 from the foreach, but the attempt to assign it to fifth element of the fourth row of the Athlete array was unsuccessful. Perl doesn't cough on this problem, it just troops along. Any ideas?

Replies are listed 'Best First'.
Re: Where is my foreach data going to?
by Enlil (Parson) on Sep 18, 2003 at 01:09 UTC
    Do you have:
    use warnings;
    near the top of your script. When I do something similiar (with warnings on)
    perl -MData::Dumper -we "$array[2,2] = 'foo'; print Dumper \@array"
    I get the warning:
    Multidimensional syntax $array[2,2] not supported at -e line 1. Useless use of a constant in void context at -e line 1. $VAR1 = [ undef, undef, 'foo' ];
    I have a feeling the syntax you want is more like:
    $athlete[$i][$j++] = $bug;

    -enlil

      Well, if I change the algorithm to :
      $qry = $DB->Query("SELECT * FROM recipes WHERE type = '$type' ORDER +BY rand() limit $quantity") || die "Got error on select: $Mysql::db_errstr\n"; + for ($i=0; $i<$qry->numrows; $i++) { @row = $qry->fetchrow or warn "recipes didn't find a matching row" +; print "\@row is assigned @row\n"; $j = 0; foreach my $bug (@row) { $athlete[$i][$j++] = $bug ; print "\$i\$j is assigned $i:$j\n"; print "\$athlete[\$i,\$j] is assigned the value $athlete[$i][$j] +\n"; print "\$bug is assigned the value $bug\n"; } } }
      then it yields:
      @row is assigned 33 Small Bunch Grapes carb 15 0.4 0.1 $i$j is assigned 4:1 Use of uninitialized value in concatenation (.) or string at ./getCurr +entNeeds.pl line 74. $athlete[$i,$j] is assigned the value $bug is assigned the value 33 $i$j is assigned 4:2 Use of uninitialized value in concatenation (.) or string at ./getCurr +entNeeds.pl line 74. $athlete[$i,$j] is assigned the value $bug is assigned the value Small Bunch Grapes $i$j is assigned 4:3 Use of uninitialized value in concatenation (.) or string at ./getCurr +entNeeds.pl line 74. $athlete[$i,$j] is assigned the value $bug is assigned the value carb $i$j is assigned 4:4 Use of uninitialized value in concatenation (.) or string at ./getCurr +entNeeds.pl line 74. $athlete[$i,$j] is assigned the value $bug is assigned the value 15 $i$j is assigned 4:5 Use of uninitialized value in concatenation (.) or string at ./getCurr +entNeeds.pl line 74. $athlete[$i,$j] is assigned the value $bug is assigned the value 0.4 $i$j is assigned 4:6 Use of uninitialized value in concatenation (.) or string at ./getCurr +entNeeds.pl line 74. $athlete[$i,$j] is assigned the value $bug is assigned the value 0.1
        The error lies in the fact that you are incrementing $j here:
        $athlete[$i][$j++] = $bug;
        The problem is that since $j is one larger than before, and thus you are not printing out the same thing (2 lines later) as what you just set. (ie $athlete[0][0] != $athlete[0][1]) so you get the warning.

        you might want to increment the $j by one at the end of the loop.

        update: I am afraid, I might have confused you so here goes. Let's pretend we are going through the inner loop on the first pass:

        $j = 0; foreach my $bug (@row) { #here $j == 0; so the following line would be #$athlete[$i][0] = $bug; $athlete[$i][$j++] = $bug #at this poing the $j == 1 because of the $j++ #on the previous line. print "\$i\$j is assignt $i:$j\n"; print "\@athlete[\$i,\$j] is assigned the value $athlete[$i][$j]\n"; #on the previous line you $j == 1 so you are refering to #$athlete[$i][1] which is not the same as what you set #but rather the value you will set the next time through. . . .
        if you change the print line to:
        print "\@athlete[\$i,\$j] is assigned the value $athlete[$i][$j-1]\n";
        you would print the value you just set, which is what I think you are trying to do.

        -enlil

        Try this instead...
        $i = 0; while (@row = $qry->fetchrow) { print "\@row is assigned @row\n"; $j = 0; foreach my $bug (@row) { $athlete[$i][$j] = $bug ; print "\$i\$j is assigned $i:$j\n"; print "\$athlete[\$i,\$j] is assigned the value $athlete[$i][$j] +\n"; print "\$bug is assigned the value $bug\n"; $j++; } $i++; }
Re: Where is my foreach data going to?
by Roger (Parson) on Sep 18, 2003 at 00:56 UTC
    Looking at your code ...
    @athlete[$i,$j++] = $bug ;
    Is actually an array slice. You probably wanted this instead:
    $athlete[$i,$j++] = $bug;
    It's pretty easy to mistake array slices for array indices.
      Did you try running
      $athlete[$i,$j++] = $bug;
      with warnings on? It doesn't mean at all what you thing it means.
      $ perl -wcle '$i = $j = 0; $athlete [$i, $j ++] = 1' Multidimensional syntax $athlete [$i, $j ++] not supported at -e l +ine 1. Useless use of a variable in void context at -e line 1. Name "main::athlete" used only once: possible typo at -e line 1. -e syntax OK

      If you want to use multi-dimensional arrays, you have to use the correct syntax:

      $athlete [$i] [$j ++] = $bug;

      Abigail

      Your change yielded these results:
      @athlete[$i,$j] is assigned the value 0.4 Small Bunch Grapes $bug is assigned the value 32 $i$j is assigned 4:2 @athlete[$i,$j] is assigned the value 0.4 carb $bug is assigned the value Medium Pear $i$j is assigned 4:3 @athlete[$i,$j] is assigned the value 0.4 15 $bug is assigned the value carb $i$j is assigned 4:4 @athlete[$i,$j] is assigned the value 0.4 0.4 $bug is assigned the value 16 $i$j is assigned 4:5 @athlete[$i,$j] is assigned the value 0.5 0.1 $bug is assigned the value 0.5 $i$j is assigned 4:6 @athlete[$i,$j] is assigned the value 0.5 $bug is assigned the value 0.2
      To be honest, I'm more confused now than I was when I first made this post.
        You need to replace all @athlete[$i,$j] with $athlete[$i,$j], even with your print statement. Because the syntax @athelete[$i,$j] is wrong. ;-)

        To understand why, you need to understand what is an array slice ...

Re: Where is my foreach data going to?
by brotherdaniel (Novice) on Sep 18, 2003 at 01:32 UTC
    OK, here's a reply to my own post. But it should reveal why I don't think it's a problem with data types. This will trim out some of the debugging code, but what you'll see it that only an occasional assignment is not made:
    @row is assigned 31 Medium Orange carb 14 2 0.2 @athlete[$i,$j] is assigned the value @athlete[$i,$j] is assigned the value Medium Orange @athlete[$i,$j] is assigned the value carb @athlete[$i,$j] is assigned the value 14 @athlete[$i,$j] is assigned the value 2 @athlete[$i,$j] is assigned the value 0.2 @row is assigned 42 1/2 c. (cooked) past carb 19.5 3.2 0.4 @athlete[$i,$j] is assigned the value 42 42 @athlete[$i,$j] is assigned the value @athlete[$i,$j] is assigned the value carb @athlete[$i,$j] is assigned the value 19.5 @athlete[$i,$j] is assigned the value 3.2 @athlete[$i,$j] is assigned the value 0.4 @row is assigned 26 1/2 c. canned peache carb 14 1 0 @athlete[$i,$j] is assigned the value 26 0.4 @athlete[$i,$j] is assigned the value 1/2 c. canned peache 1/2 c. cann +ed peache @athlete[$i,$j] is assigned the value @athlete[$i,$j] is assigned the value 14 @athlete[$i,$j] is assigned the value 1 @athlete[$i,$j] is assigned the value 0 @row is assigned 6 White Bread III carb 24.5 4.1 2.3 @athlete[$i,$j] is assigned the value 6 @athlete[$i,$j] is assigned the value White Bread III 0 @athlete[$i,$j] is assigned the value carb carb @athlete[$i,$j] is assigned the value @athlete[$i,$j] is assigned the value 4.1 @athlete[$i,$j] is assigned the value 2.3 @row is assigned 20 Marias Spanish Rice carb 42.4 4.3 5 @athlete[$i,$j] is assigned the value 20 @athlete[$i,$j] is assigned the value Marias Spanish Rice @athlete[$i,$j] is assigned the value carb 2.3 @athlete[$i,$j] is assigned the value 42.4 42.4 @athlete[$i,$j] is assigned the value @athlete[$i,$j] is assigned the value 5
    See what I mean? It just seems to almost be caching or writing out of order. I'm sure it's my mistake, but I sure don't know why it's doing this. These are the results from my original code base.
      It has everything to do with data types! @athelete[$i,$j], $athelete[$i, $j] and $athelete[$i][$j] are completely different. Try to use the Data::Dumper to investigate why:
      use strict; use Data::Dumper; my @array; for (my $i=0;$i<2;$i++) { for (my $j=0;$j<2;$j++) { @array[$i, $j] = "$i.$j"; } } print "Case 1...\n"; print Dumper(@array); for (my $i=0;$i<2;$i++) { for (my $j=0;$j<2;$j++) { $array[$i][$j] = "$i . $j"; } } print "Case 2...\n"; print Dumper(@array); for (my $i=0;$i<2;$i++) { for (my $j=0;$j<2;$j++) { $array[$i, $j] = "$i . $j"; } } print "Case 3...\n"; print Dumper(@array);
      You will get -
      Case 1... $VAR1 = undef; $VAR2 = undef; Case 2... $VAR1 = [ '0 . 0', '0 . 1' ]; $VAR2 = [ '1 . 0', '1 . 1' ]; Case 3... $VAR1 = '1 . 0'; $VAR2 = '1 . 1';
      As you can see, only case 2 gives you what you want, a two dimensional array.
        Just one point , when using Data::Dumper::Dumper() to dump an array or a hash, it is often better to pass a reference to the hash/array, as the output looks more like the original data structure - and you avoid the copying overhead of call-by-value vs call-by-refernce
        use Data::Dumper; my @array = (1,2,3,4,5,6,7); print Dumper(\@array); my %hash; # below is a hash slice - you should learn about these @hash{@array} = @array;# a hash whose keys == its values print Dumper(\%hash);
        results in the output
        $VAR1 = [ 1, 2, 3, 4, 5, 6, 7 ]; $VAR1 = { '7' => 7, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6 };
        which to my eyes seems nicer
Re: Where is my foreach data going to?
by Beechbone (Friar) on Sep 18, 2003 at 17:39 UTC
    Ok, we cleaned up the @/$/[,]/[][] problem. But why don't you just write:
    for ($i=0; $i<$qry->numrows; $i++) { @row = $qry->fetchrow or warn '...'; print "\@row is assigned @row\n"; $athlete[$i] = [ @row ]; }
    or even perlier:
    for my $i (0 .. $qry->numrows - 1) { @row = $qry->fetchrow() or warn '...'; $athlete[$i] = [ @row ]; }
    or (I hate array subscripts):
    for (1 .. $qry->numrows) { @row = $qry->fetchrow() or warn '...'; push @$athlete, [ @row ]; }
    ok, no2 looks better ;)

    Update: Oops, and again i coded rusbish. Fixed code no3, now it no longer looks bad ;)