Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

shift array, element deleted but then comes back! huh? 1

Status
Not open for further replies.

m4trix

Vendor
Jul 31, 2002
84
CA
I'm hoping someone can explain why an array with one element, when 'shifted' in a subroutine continues to contain one element once the subroutine finishes.

Consider the following:
Code:
use Data::Dumper;
@arrayone = [10, [1, 2, 3]];
@arraytwo = ();
$number = 10;

print "OUTSIDE BEFORE\n======\n".Dumper(@arrayone)."\n";
&DoStuff;
print "======\nOUTSIDE AFTER\n======\n".Dumper(@arrayone)."\n";

sub DoStuff {
    if (@arrayone) {
        while ($arrayone[0][0] == $number) {
                print "======\nINSIDE BEFORE\n======\n".Dumper(@arrayone)."\n";
            my $temparr = shift(@arrayone);
                print "======\nINSIDE AFTER\n======\n".Dumper(@arrayone)."\n";
            push (@arraytwo, $temparr->[1]);
}}}

Once run, it produces the following output:
Code:
OUTSIDE BEFORE
======
$VAR1 = [
          10,
          [
            1,
            2,
            3
          ]
        ];

======
INSIDE BEFORE
======
$VAR1 = [
          10,
          [
            1,
            2,
            3
          ]
        ];

======
INSIDE AFTER
======

======
OUTSIDE AFTER
======
$VAR1 = [];

Note that INSIDE BEFORE contains an element, and INSIDE AFTER does not (as I would expect - when the only element is shifted off the array). But as soon as the subroutine returns to the main program, the array contains an empty element (shown below OUTSIDE AFTER).

Why is this, and how can I get around it?
thanks
 
Its doing that because it's outside the "while" loop, but why it does that because it's outside the loop I don't know. But if you put that last print statement inside the while loop it prints nothing.

Code:
my @arrayone = [10, [1, 2, 3]];
my @arraytwo = ();
my $number = 10;
print "OUTSIDE BEFORE\n======\n".Dumper(@arrayone)."\n";
&DoStuff;
sub DoStuff {
    if (@arrayone) {
        while ($arrayone[0][0] == $number) {
                print "======\nINSIDE BEFORE\n======\n".Dumper(@arrayone)."\n";
            my $temparr = shift(@arrayone);
                print "======\nINSIDE AFTER\n======\n".Dumper(@arrayone)."\n";
            push (@arraytwo, $temparr->[1]);
                print "======\nOUTSIDE AFTER\n======\n".Dumper(@arrayone)."\n";
        }
    }
}

prints:

Code:
OUTSIDE BEFORE
======
$VAR1 = [
          10,
          [
            1,
            2,
            3
          ]
        ];

======
INSIDE BEFORE
======
$VAR1 = [
          10,
          [
            1,
            2,
            3
          ]
        ];

======
INSIDE AFTER
======

======
OUTSIDE AFTER
======
 
Apparently the test in the while loop
while ($arrayone[0][0] == $number) {
after the sole element has been shifted off causes the element to "autovivify." It's as though perl needs to put something there so it can do the comparison. You can get around this by checking if the array is empty before doing the comparison:
Code:
use Data::Dumper;
@arrayone = [10, [1, 2, 3]];
@arraytwo = ();
$number = 10;

print "OUTSIDE BEFORE\n======\n".Dumper(@arrayone)."\n";
&DoStuff;
print "======\nOUTSIDE AFTER\n======\n".Dumper(@arrayone)."\n";

sub DoStuff {
    [b]while (@arrayone && $arrayone[0][0] == $number) {[/b]
        print "======\nINSIDE BEFORE\n======\n".Dumper(@arrayone)."\n";
        $temparr = shift(@arrayone);
        print "======\nINSIDE AFTER\n======\n".Dumper(@arrayone)."\n";
        push (@arraytwo, $temparr->[1]);
    }
}
This way the comparison never happens, so no autovivification.

A couple comments:
1. The assignment @arrayone = [10, [1, 2, 3]]; is a bit weird. @arrayone is an array, but what you're assigning to it isn't: it's a reference to an anonymous array. Perl does what you mean here, and converts it to @arrayone = ([10, [1, 2, 3]]), but you really should write it that way in the first place.

2. You should be using strict and warnings. When I turned on warnings aand got an "uninitialized value" warning on the second while test, that's what tipped me off. Very helpful.

Here's the output with the change to the while condition:
Code:
OUTSIDE BEFORE
======
$VAR1 = [
          10,
          [
            1,
            2,
            3
          ]
        ];

======
INSIDE BEFORE
======
$VAR1 = [
          10,
          [
            1,
            2,
            3
          ]
        ];

======
INSIDE AFTER
======

======
OUTSIDE AFTER
======
HTH

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top