Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re: shift v. indexing into an array

by Joost (Canon)
on Nov 15, 2009 at 21:58 UTC ( [id://807312]=note: print w/replies, xml ) Need Help??


in reply to shift v. indexing into an array

The reason seasoned programmers avoid indexes when they can is because there are nice abstractions for many common cases that are easy to understand, make the intent of the code clearer and are more concise.

Perl's builtins include map and grep as simple examples: if you want to filter out some information in a large or small array it's clearer to use grep, if you want to transform an array into a new one, it's clearer to use map.

If you want to modify the array in place, you can generally use simple for(each): for (@array) { $_ = $_+1 }. You really only want to use indexing if the index is more than just the index in your algorithm. It's also sometimes the case that using an index makes it easier to do operations on related elements in a list (though that has more to do with a lack of builtins that deal with groups of elements - you can easily write functions that handle the problem in a more generic way).

My rule of thumb, inspired by more functional languages like Scheme, is this: most of the time, you want to produce a new list/array, and that entails you probably don't want to use for() with or without indexes. But when you instead want to produce side-effects (like modifying the original array, or printing each element) you do want to use for().

I try to use while(defined shift(@array)) etc only on buffers and the like that get filled in one place and are "simultaniously" drained in another, and shift() on its own pretty much only when reading function arguments.

On the subject of shift() - perl arrays keep a "start-of-array" number in their datastructures, so using shift() usually doesn't move any items at all and it's generally pretty efficient to shift() even very large arrays. See Perlguts illustrated. I'm assuming shift/push combos move stuff around every once in a while, since I write code that depends on that behaviour and it seems to work, but I'm only 90% certain on that.

As for where to declare variables: declare them in the smallest block you can, if only because the memory they're using can potentially be freed when the code leaves that block of code.

Don't worry about potential cpu problems there unless you have serious reasons to think they're any problem in a real program. On the whole of your program's runtime they're almost always a completely trivial concern, and there are even potential optimizations to make on "locally declared" variables - though perl doesn't usually make those optimizations. Also note that looping over a lexical variable declaration does not 're-declare' that variable. It just gets marked as uninitialized.

Replies are listed 'Best First'.
Re^2: shift v. indexing into an array
by ikegami (Patriarch) on Nov 15, 2009 at 22:34 UTC

    perl arrays keep a "start-of-array" number in their datastructures, so using shift() usually doesn't move any items at all and it's generally pretty efficient to shift() even very large arrays.

    shift never moves any items, and thus it's extremely efficient no matter the size of the array.

    @a = qw( a b c ); +---+---+---+---+ @a = | a | b | c | X | ( X = spare ) +---+---+---+---+ ^ ^ | | start end shift @a; +---+---+---+---+ @a = | X | b | c | X | +---+---+---+---+ ^ ^

    I'm assuming shift/push combos move stuff around every once in a while, since I write code that depends on that behaviour and it seems to work, but I'm only 90% certain on that.

    It's not the shift/push combo, it's push alone that causes the moving.

    For efficiency, arrays can have more elements allocated than necessary. If a push is performed, these spare elements will be used. If a push is performed and there no spare elements, a new bigger array is allocated and the elements (pointers) are moved to the new array. This occurs whether shift was used or not.

    [ continuing from above ] push @a, 'd'; +---+---+---+---+ @a = | X | b | c | d | +---+---+---+---+ ^ ^ push @a, 'e'; -> No more space! Re-allocation occurs. -> $new_buf_size = $old_buf_size * 2 + 4 -> Pointers to elements are quickly copied to newly allocated buffer. +---+---+---+---+ | X | b | c | d | +---+---+---+---+ / / / / / / / / / v v v +---+---+---+---+---+---+---+---+---+---+---+---+ @a = | b | c | d | e | X | X | X | X | X | X | X | X | +---+---+---+---+---+---+---+---+---+---+---+---+ ^ ^
Re^2: shift v. indexing into an array
by 7stud (Deacon) on Nov 18, 2009 at 10:34 UTC
    Also note that looping over a lexical variable declaration does not 're-declare' that variable. It just gets marked as uninitialized.

    I was reading the Monk tutorial "Coping with Scoping", and I found an example which is relevant to this discussion:

    Every time control reaches a my declaration, Perl creates a new, fresh variable. For example, this code prints x=1 fifty times:

    for (1 .. 50) { my $x; $x++; print "x=$x\n"; }

    You get a new $x, initialized to undef, every time through the loop.

    If the declaration were outside the loop, control would only pass by it once, so there would only be one variable:

    { my $x; for (1 .. 50) { $x++; print "x=$x\n"; } }

    This prints x=1, x=2, x=3, ... x=50.

    That seems at odds with what you are saying. In any case, there are situations where declaring a my variable inside a loop can cause problems.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://807312]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (4)
As of 2024-03-29 14:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found