Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

loop array excluding some elements

by IB2017 (Scribe)
on Mar 08, 2018 at 17:41 UTC ( #1210521=perlquestion: print w/replies, xml ) Need Help??
IB2017 has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks

Is there any beeter way (one liner?) to loop an array and jumping some elements? This is the code I normally use but it is not that elegant...

foreach (@SlectedColumns[1..$NrCoumns]) { if ($_!=0){#jump if element is 0 #do something } }

Replies are listed 'Best First'.
Re: loop array excluding some elements
by Eily (Prior) on Mar 08, 2018 at 17:45 UTC

    grep in list context (eg, used in a for) will create a new list by selecting elements in its input that match a condition. IE:

    foreach (grep { $_ != 0 } @SlectedColumns[1..$NrCoumns]) { # Only non zero elements here }

    Edit: and if your input is only numbers, and the content of the loop is just one EXPR, you can even write: print "I'm priting $_!\n" for grep $_, @SlectedColumns[1..$NrCoumns];

Re: loop array excluding some elements
by AnomalousMonk (Chancellor) on Mar 08, 2018 at 17:58 UTC

    I like this sort of pattern (update: maybe "style" would be a better word to use here than "pattern"):

    c:\@Work\Perl\monks>perl -wMstrict -le "my @SlectedColumns = (9, 7, 6, 0, 5, 0, 4, 3, 2, 0, 1, 9, 9); my $end_index = 10; ;; COLUMN: for my $col (@SlectedColumns[1 .. $end_index]) { next COLUMN unless $col != 0; print qq{do something with col $col}; } " do something with col 7 do something with col 6 do something with col 5 do something with col 4 do something with col 3 do something with col 2 do something with col 1
    An  if (COND) { ... } structure with its messy indentation and visual presentation is avoided, and cyclomatic complexity is reduced.

    Update 1: In my experience, this pattern turns up quite often in a context like:

    use constant RX_COMMENT => qr{ ... }xms; ... ... sub is_valid { my ($string, ) = @_; return $string =~ RX_COMMENT ? 0 : $string =~ RX_BLANK_STRING ? 0 : $string =~ RX_VALID_LINE ? 1 : die "invalid: '$string'" # default ; } ... ... LINE: while (my $line = <$fh>) { next LINE unless is_valid($line); do_something_with_known_valid($line); do_something_else_with($line); ... } # end while LINE

    Update 2: This is my 4000th writeup!


    Give a man a fish:  <%-{-{-{-<

      This is my 4000th writeup!
      Congratulations. :)

      This is my 4000th writeup!

      I'm glad to have read many of them.

      Cheers, Sören

      Créateur des bugs mobiles - let loose once, run everywhere.
      (hooked on the Perl Programming language)

Re: loop array excluding some elements
by Discipulus (Monsignor) on Mar 08, 2018 at 18:15 UTC
    Hello IB2017,

    you are looking for wisdom, not for elegance! ;=)

    Elegance can be your enemy: better looking for efficiency and readability.

    You already received a wise answer by Eily++ about grep

    If your do_something is short as print you can consider also the unless postscript form:

    foreach my $ele (@SlectedColumns[1..$NrCoumns]) { do_something unless $ele == 0; }

    It's an handy and readable syntax.

    If the loop is complex and actions are more, something very similar to your example is a wise form to express some logic: a good principle exit loop early

    foreach my $ele(@SlectedColumns[1..$NrCoumns]) { # exit soon next if $ele == 0; next unless defined $ele; .... }

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: loop array excluding some elements
by karlgoethebier (Monsignor) on Mar 10, 2018 at 19:42 UTC
    "...one liner?..."

    Probably you want something like this?

    perl -MData::Dump -Mstrict  -e 'dd map { my $i = $_; ...;} grep { $_ != 0 } ( 1, 2, 3, 5, 0, 7, 8, 9, 10 );'

    The stuff you want to do with $i goes here: ...; See also Common Causes for "Modification of a read-only value attempted".

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: loop array excluding some elements
by karthiknix (Acolyte) on Mar 09, 2018 at 10:00 UTC

    you can use map function in PERL to do a one line parsing of array. Below is an example which is similar to you code and you can extend to what ever you want to add in the if loop.

    @tt = (1,2,3,5,0,7,8,9,10); map{if($_!=0){print "I did something when it is not zero\n";}}@tt;

      But how is that better (in the sense of more clear or familiar) than, say,
          print "do something with $_ \n" for grep $_ != 0, @tt;
      (already suggested by Eily here)?


      Give a man a fish:  <%-{-{-{-<

        First it is one liner. Second you can add logic you want under these parentheses map{....}@yourarray. But on your one liner with grep you are just doing a print "do something ...".

Re: loop array excluding some elements
by Anonymous Monk on Mar 09, 2018 at 14:08 UTC
    I don't mind at all using loops, and the next and last verbs work quite well here. You can even use some verbiage that's fairly peculiar to perl, such as:
    next unless ($_ == 0);

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1210521]
Approved by haukex
Front-paged by haukex
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (6)
As of 2018-07-21 15:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?















    Results (449 votes). Check out past polls.

    Notices?