Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

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; .... }


    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
    " 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?

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (7)
As of 2018-09-19 20:54 GMT
Find Nodes?
    Voting Booth?
    Eventually, "covfefe" will come to mean:

    Results (170 votes). Check out past polls.

    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!