Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

pop and shift not reversible

by gannett (Novice)
on Mar 20, 2020 at 10:42 UTC ( #11114509=perlquestion: print w/replies, xml ) Need Help??

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

I was stuck debugging a larger program but finally located the cause of the misunderstanding. The code takes one element off an array then process the rest of the array using while ( $next = pop @x) { Process element in $next }; I noticed that in some circumstances an element was being dropped. After some digging I found that the behaviour of shift and pop are not reversibly consistent in this context. The code works as expected using shift but pop stops when the element value 0 is processed.

Can anyone explain why pop behaves differently from shift in this context ?

In the demonstrator code below the array x delivers 2 elements but all the rest deliver 3 elements.

This is perl 5, version 22, subversion 1 (v5.22.1) built for darwin-thread-multi-2level on a MacBookPro
use strict; my @a = ( 0,1,2,3 ) ; my @b = ( 1,2,3,4 ); my @x = ( 0,1,2,3 ) ; my @y = ( 1,2,3,4 ); my @r = reverse @a; my $next = 0 ; my $first = 0; my $first = shift @a ; print "a $#a shift ",$first,"->"; while ( $next = shift @a ) { print ",",$next } print "\n"; $first = shift @b ; print "b $#b shift ",$first,"->"; while ( $next = shift @b ) { print ",",$next } print "\n"; $first = pop @x ; print "x $#x pop ",$first,"->"; while ( $next = pop @x ) { print ",",$next } print "\n"; $first = pop @y ; print "y $#y pop ",$first,"->"; while ( $next = pop @y ) { print ",",$next } print "\n"; $first = pop @r ; print "r $#r pop ",$first,"->"; while ( $next = pop @r ) { print ",",$next } print "\n"; Gives --- >>>>> See line starting x $ perl test.pl a 2 shift 0->,1,2,3 b 2 shift 1->,2,3,4 x 2 pop 3->,2,1 y 2 pop 4->,3,2,1 r 2 pop 0->,1,2,3

Replies are listed 'Best First'.
Re: pop and shift not reversible
by hippo (Chancellor) on Mar 20, 2020 at 10:59 UTC

    You are checking the truth of $next = pop @x rather than the definedness. 0 is false.

    use strict; use warnings; my @x = (0, 1, 2, 3); my $next; my $first = pop @x ; print "x $#x pop ",$first,"->"; while ( $next = pop @x ) { print ",",$next } print "\n"; @x = (0, 1, 2, 3); $first = pop @x ; print "x $#x pop ",$first,"->"; while ( defined ($next = pop @x) ) { print ",",$next } print "\n";
Re: pop and shift not reversible
by BillKSmith (Prior) on Mar 20, 2020 at 14:42 UTC
Re: pop and shift not reversible
by talexb (Canon) on Mar 20, 2020 at 13:39 UTC

    You may have got this already, but I'm going to explain without code fragments. pop takes an element off the end of an array; it matches up with push, which adds an element to the end of an array. shift takes an element off the beginning of an array; it matches up with unshift (OK that one is maybe a little clumsily named), which adds an element to the beginning of an array.

    So, to answer the premise your title proposes, Nope -- reverse pop with push, and reverse shift with unshift. Still not convinced? Hop into the debugger and try a few examples, live, and see how Perl works. :)

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: pop and shift not reversible
by Anonymous Monk on Mar 20, 2020 at 14:05 UTC

    I believe you will find that pop and shift are reversible, but your code is not. Specifically, if you reverse the data in your toy arrays, it will be pop that processes the entire array, and shift that stops early.

    Expanding on what has been said previously, you seem to be coding in the belief that while ( my $next = pop @x ) { ... } stops when the array is empty. In fact, it stops when it encounters the first false value. In Perl, "false" means undef, 0, or ''.

    This is why the correct loop is while ( @x ) { my $next = pop @x; ... } (or shift, as the case may be.)

Re: pop and shift not reversible ( while @array )
by Anonymous Monk on Mar 20, 2020 at 12:19 UTC
    while( @array ){ my $next = shift @array; }
      Thank you for your combined wisdom. I see this also works but looks a bit inelegant.
      my @q = ( 1,2,0,4 ); $first = pop @q; print "q $#q pop ",$first,"->"; while ($#q+1) { $next = pop @q ; print ",",$next }; ---- Gives q 2 pop 4->,0,2,1
      I would be using the offered solution.
      while( @array ) { my $next = shift @array; }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11114509]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (8)
As of 2020-04-04 12:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    The most amusing oxymoron is:
















    Results (32 votes). Check out past polls.

    Notices?