Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Build your array with push

by PhilHibbs (Hermit)
on Jan 31, 2006 at 14:21 UTC ( #526753=perlmeditation: print w/ replies, xml ) Need Help??

Some ideas are so simple that they sometimes do not seem to be worth mentioning. This is one of them.

I don't write this:

my @folk = ("Hibbs", "Daglish", "Schwartz", "Vroom");
I write this:
my @folk = (); push (@folk, "Hibbs"); push (@folk, "Daglish"); push (@folk, "Schwartz"); push (@folk, "Vroom");
Why? It's easier to maintain. You can insert or remove any single line easily, at the beginning, middle, or end. You can remove all the hard-coded lines, or move them to a later point (inside a loop, maybe).

The down-side is that the array name has to be repeated on each line, and there is probably a slight performance penalty.

Now you're going to show me something that uses "qw", aren't you? OK, go ahead, but don't forget to show me how it looks when an entry contains spaces.

Update: make it look less like advice, since it turns out there are better constructs

Comment on Build your array with push
Select or Download Code
Re: Build your array with push
by Corion (Pope) on Jan 31, 2006 at 14:26 UTC

    I don't like the push way of constructing arrays. I use the following idioms:

    my @array = ( "Hibbs", "Daglish", "Schwartz", "Vroom", );

    ... which works well for adding in any place, and also (un)commenting entries. If I'm sure there are no newlines/whitespace-only elements in the array needed, I also may use the following:

    my @array = grep { /\S/ } split /\n/, ' foo bar baz and so on ';

    depending on how my input data gets delivered (multi-column Excel data fits better into this model for example).

      my @array = ( "Hibbs", "Daglish", "Schwartz", "Vroom", );

      I agree. And the little thing that makes this really work well is training oneself to add that trailing comma (after "Vroom") to the last entry. (Ditto for hashes entries, too.)

      -xdg

      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      Something in me really doesn't like that trailing comma, which I wouldn't have expected to work. I suspect it's just an old habit, as it doesn't work in C & C++, which is still there lurking at the back of my mind and occasionally poisoning the Perl code that I write. OK, I'll try and get used to it, and thanks for introducing me to it - I trust that it really has no effect.

      Now to get back some of that lost XP by upvoting the helpful replies...
       ah, I like being a Friar anyway, it goes with my T-shirt.

        you don't have to merely trust; it's documented in perldata:
        You may have an optional comma before the closing parenthesis of a list literal
        In fact, you can have extra commas anywhere you want in a list except (for reasons I can't explain) at the very front of it. They will not cause undef items to be created, nor will including nested empty lists.
        my @items = ((),,,,5); print "<$_>\n" for @items; # prints only one item

        Caution: Contents may have been coded under pressure.

        Actually it does work in C, and that's most likely where perl picked up the habit too. One reason it's very useful is when you're generating code with macros, it's much easier to append commas to things than to insert them between things.

        --
        integral, resident of freenode's #perl
        
      I don't like the push way of constructing arrays.

      You think that's bad, I once had to maintain a program that did this:

      my @array; $array[$#array] = "Hibbs"; $array[$#array] = "Daglish"; $array[$#array] = "Schwartz"; $array[$#array] = "Vroom"; ...
      And so on for about 30 lines.

      One of the few times I felt justified in regexing some code.

        Woah, woah, woah. That code just replaces the last element multiple times. Did you maybe mean
        $array[@array] = "Hibbs";
        or
        $array[++$#array] = "Hibbs";
        ?

        Caution: Contents may have been coded under pressure.

      I use the former idiom as well, but I've run across this style a couple of times, too:

      my @array = ( 'Hibbs' ,'Daglish' ,'Schwartz' ,'Vroom' );

      The one time I had the chance to actually ask a coder about that style, he gave me two rationales. First, he liked it because of a string-cat convention that's similar:

      my $string = 'this is a very long string that has a certain number ' .$number .' of segments.' ."\n";

      In print statements, this coder often mirrored that convention using commas instead of periods to pass the list of strings to print. (This is apparently faster, though it smacks of premature optimization to me. But I digress.)

      The second reason was that he found the trailing comma to be confusing; by moving commas to the front, he provided a visual reminder to put the comma in when adding to the list but without the "confusing" trailing comma. To each their own, I guess.

      Anyone have thoughts on this style? Just curious as to what advantages/disadvantages there might be.

      <-radiant.matrix->
      A collection of thoughts and links from the minds of geeks
      The Code that can be seen is not the true Code
      I haven't found a problem yet that can't be solved by a well-placed trebuchet

        That doesn't really help here since you can't insert at the top safely.

        The style has been called The Perlish Coding Style. Accoding to that document, the following would be the proper alignment:

        { my @array = ( 'Hibbs' , 'Daglish' , 'Schwartz' , 'Vroom' ) ; my $string = 'this is a very long string that has a certain number ' . $number . ' of segments.' . "\n" }
Re: Build your array with push
by blazar (Canon) on Jan 31, 2006 at 14:30 UTC

    Personally I don't see any evident maintainability advantage that initialization-by-pushes buys me over the "standard" one that any decent text editor couldn't give me just as easily. The only "problem", if you really, really want to call it a problem, may have to do with the first and last entry. If you're really, really that concerned about the few extra keystrokes these may involve, then you how 'bout

    my @folk = ( "Hibbs", "Daglish", "Schwartz", "Vroom", );

    instead?

    Now you're going to show me something that uses "qw", aren't you? OK, go ahead, but don't forget to show me how it looks when an entry contains spaces.

    What's the problem? If I have a set of "words" (in the qw// acceptation!) then I use qw//. If I have a set of "strings" some of which contain spaces or may cointain spaces in a future re-editing of the code, then I don't. Period!

    Oh, and in the unlikely case I implemented a list with qw// and later it turned out that some entries must contain spaces, I have quite a few workarounds none of which is likely to cause any major nor minor damage to my hands, sight, brain, etc.

Re: Build your array with push
by demerphq (Chancellor) on Jan 31, 2006 at 14:35 UTC

    As japhy so kindly pointed out, the following:

    my @folk = qw(Hibbs Daglish Schwartz Vroom), "Node Reaper"; my @folk = map {s/_/ /g; $_} qw(Hibbs Daglish Schwartz Vroom Node_Reaper);

    should have been written

    my @folk = (qw(Hibbs Daglish Schwartz Vroom), "Node Reaper"); my @folk = map {(my $s=$_)=~s/_/ /g; $s} qw(Hibbs Daglish Schwartz Vroom Node_Reaper);

    Thatll teach me not to be a smarty pants.

    ---
    $world=~s/war/peace/g

      First one doesn't work, second one is grasping at straws.

      Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
      How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

        Neither work. Second one has the dreaded can't modify read only string error. Which is a good example of the issues the OP was making I guess. Sigh, i should know better for both of these too. :-(

        I will quibble with the "grasping at straws" comment tho. I think this approach often is just fine for dealing with spaces in a qw() string.

        ---
        $world=~s/war/peace/g

Re: Build your array with push
by Fletch (Chancellor) on Jan 31, 2006 at 16:06 UTC
    use YAML qw( Load ); my @folk = @{ Load( <<EOT ) }; - Hibbs - Daglish - Schwartz - Vroom - Spaces too! EOT
Re: Build your array with push
by Anonymous Monk on Jan 31, 2006 at 16:37 UTC
    Yeah, but what if you've misspelled a name? Shouldn't it be easy to fix those kinds of mistakes? That's why I'd recommend formatting like...
    my @folk = (); push (@folk, "H". "i". "b". "b". "s" ); push (@folk, "D". "a". "g". "l". "i". "s". "h" );
    ...etc. Of course that's also problematic if you want to edit an individual letter. So I find the style below a bit better (especially when using a modern editor like edlin). Plus it uses a more descriptive name than the bland "@folk"...
    push (@Hibbs_Daglish_Schwartz_Vroom, chr(0b1001000). chr(0b1101001). chr(0b1100010). chr(0b1100010). chr(0b1110011) ); push (@Hibbs_Daglish_Schwartz_Vroom, chr(0b1000100). chr(0b1100001). chr(0b1100111). chr(0b1101100). chr(0b1101001). chr(0b1110011). chr(0b1101000) ); push (@Hibbs_Daglish_Schwartz_Vroom, chr(0b1010011). chr(0b1100011). chr(0b1101000). chr(0b1110111). chr(0b1100001). chr(0b1110010). chr(0b1110100). chr(0b1111010) ); push (@Hibbs_Daglish_Schwartz_Vroom, chr(0b1010110). chr(0b1110010). chr(0b1101111). chr(0b1101111). chr(0b1101101) );
      Of course, if you want to get rid of all that pesky horizontal scrolling you could pass something like the following through cpp...
      p\ u\ s\ h\ (\ @\ H\ i\ b\ b\ s\ _\ D\ a\ g\ l\ i\ s\ h\ _\ S\ c\ h\ w\ a\ r\ t\ z\ _\ V\ r\ o\ o\ m\ ,\ c\ h\ r\ (\ 0\ b\ 1\ 0\ 0\ 1\ 0\ 0\ 0\ )\ )\ ;\

        That won't work. Perl is not C.

      That style of code is totally ugly and unusable. What if your original list of data erroneously switched two characters and you now have to swap the last and next-to-last character? This coding style is flawed in that aspect. You should use the following coding style instead:

      push (@Hibbs_Daglish_Schwartz_Vroom, "" . chr(0b1010110) . chr(0b1110010) . chr(0b1101111) . chr(0b1101111) . chr(0b1101101) );

      Actually I use this coding style when manipulating SQL SELECT statements:

      SELECT monkey, bananas from my_table where 1 = 1 and flung_poo is null and size > 800 ;
        That style of code is totally ugly and unusable [...] You should use the following coding style instead:

        No, no, no! Yours is better than the previous alternatives but one may still get confused when swapping bits. And all those calls to chr, oh my! Now pack can do all this for cheap. Thus you should use the following coding style instead:

        push @Hibbs_Daglish_Schwartz_Vroom, pack qw/(B8)* 01010110 01110010 01101111 01101111 01101101 /;

        Except that one would almost certainly want to write a specialized sub to do this, should he later change his mind with respect to the order in which to store bits into chars, chars into strings and strings into the array:

        sub insert (\@@) { my $arr=shift; push @$arr, pack '(B8)*', @_; } # ... insert @Hibbs_Daglish_Schwartz_Vroom, qw/ 01010110 01110010 01101111 01101111 01101101 /;
Re: Build your array with push
by Anonymous Monk on Jan 31, 2006 at 16:59 UTC
    my @folk = ( Hibbs => Daglish => Schwartz => Vroom => "and with spaces" );

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://526753]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2014-07-24 02:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (156 votes), past polls