http://qs321.pair.com?node_id=759433

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

Monks, hi there!

I followed a node here while ago and one part of the code got me going, I wish someone could show me a better way to accomplish this issue, I can't figure it out. Is got to be a better and simpler way to do this.
It needs to place a space in the $ref_b to make sure consistency when generating a report out of this and avoid errors.

use strict; use warnings; use Data::Dumper; my $ref_a = [ [ qw/a b c/ ], [ qw/d e f/ ], [ qw/g h i/ ], [ qw/x y z/ ], [ qw/3 4 5/ ], [ qw/6 7 9/ ], ]; my $ref_b = [ [ qw/j k l/ ], [ qw/m n o/ ], [ qw/p q r/ ], ]; for my $i (0..$#$ref_a) { push @{$ref_a->[$i]}, @{$ref_b->[$i]}; } print Dumper($ref_a);

Replies are listed 'Best First'.
Re: Undefined Array Reference
by Nkuvu (Priest) on Apr 22, 2009 at 23:40 UTC

    It took me a minute or three to figure out what the problem was. Correct me if I'm wrong: When you run the code, you get a "Can't use an undefined value as an ARRAY reference at scriptname.pl line 21" error and you aren't sure why.

    I can answer that part -- but what I can't answer is exactly what you're trying to do. The for loop is iterating from 0 to the maximum index in $ref_a. That reference is larger than what you'll find in $ref_b. Some simple print statement debugging will help show what I mean:

    print "ref_a: ", $#$ref_a, "\nref_b: ", $#$ref_b, "\n"; for my $i (0..$#$ref_a) { print "Reading element $i\n"; push @{$ref_a->[$i]}, @{$ref_b->[$i]}; }

    With some output:

    ref_a: 5 ref_b: 2 Reading element 0 Reading element 1 Reading element 2 Reading element 3 Can't use an undefined value as an ARRAY reference at scriptname.pl li +ne 23

    To correct this problem, you can just choose the minimum of the two ref_a/b indices. But since I don't know what your goal is, I don't know if this will correct your issue.

      The reason for that is a query result from a database, each array ref, since I can not join these tables, are each from these tables, and I don't know how many records each one will be returning, that is the reason for this sample code.
        I'd really like to know why you can't join the tables...
Re: Undefined Array Reference
by almut (Canon) on Apr 22, 2009 at 23:58 UTC

    Maybe something like this?

    ... for my $i (0..$#$ref_a) { push @{$ref_a->[$i]}, @{ ref($ref_b->[$i]) eq 'ARRAY' ? $ref_b->[$i] : [(' ') x 3] }; } print Dumper($ref_a); __END__ $VAR1 = [ [ 'a', 'b', 'c', 'j', 'k', 'l' ], [ 'd', 'e', 'f', 'm', 'n', 'o' ], [ 'g', 'h', 'i', 'p', 'q', 'r' ], [ 'x', 'y', 'z', ' ', ' ', ' ' ], [ '3', '4', '5', ' ', ' ', ' ' ], [ '6', '7', '9', ' ', ' ', ' ' ] ];

    ... my interpretation of the "space in the $ref_b"  :)

      Another interpretation would be "when ref_b runs out of data, don't do anything more to ref_a".

      If this is what's needed then:

      for my $i (0..$#$ref_a) { push @{$ref_a->[$i]}, @{$ref_b->[$i] || []}; }
      Ie, if @{$ref_b} hasn't got as many members as @{$ref_a}, then at some point $ref_b->[$i] is undef, so dereference a reference to an empty array in that case.

      (I also tried to use || last there (ie exit the loop early) but that comes up with a "bizarre" error message.)

      If it's also possible for ref_b to have more members than ref_a, and the extras should be tacked on verbatim, then the range of the for loop needs to be adjusted to cover them. Here's one option which is moderately readable:

      for my $i (0.. ($#$ref_a > $#$ref_b ? $#$ref_a : $#$ref_b) ) {
      Handily, extra elements appear in ref_a automatically as needed, so there's no need for a || [] on the first argument to push.

      Update: Re-reading the thread made me realise that because of the autovivification in ref_a, ikegami's suggestion does acheive all this (I think) but much more subtly. Too subtle for me the first time round ;-)

      --
      use JAPH;
      print JAPH::asString();

Re: Undefined Array Reference
by syphilis (Archbishop) on Apr 22, 2009 at 23:42 UTC
    In your for loop, $ref_b->[$i] doesn't exist for $i greater than 2. Consequently, as soon as $i == 3, you get the error you see.

    What do you want to push onto @{$ref_a->[$i]} when $i is 3, 4 or 5 ?

    Cheers,
    Rob
      Maybe nothing?
      | v for my $i (0..$#$ref_b) { push @{$ref_a->[$i]}, @{$ref_b->[$i]}; }
Re: Undefined Array Reference
by lostjimmy (Chaplain) on Apr 23, 2009 at 13:00 UTC
Re: Undefined Array Reference
by bichonfrise74 (Vicar) on Apr 23, 2009 at 01:27 UTC
    Because the number of elements for each array references are not the same which is why you are getting the error.
Re: Undefined Array Reference
by Marshall (Canon) on Apr 25, 2009 at 11:05 UTC
    Since your code doesn't produce a result and you haven't told us what you want, this is a guessing game.

    On style, this: for my $i (0..$#$ref_a) is a super red flag. This sort of loop variable is a "non-Perl" way to do things and $# is deprecated anyway.

    I guessed that you wanted to merge the $ref_b stuff into the $ref_a stuff and get a revised version of $ref_a reflecting a new sorted version of those updates (eg "j,k,l" should come before "x,y,z"),like this:

    3 4 5 6 7 9 a b c d e f g h i j k l m n o p q r x y z

    The code below shows how to do that..and what to do if you want numbers to appear after letters (sort order change)...