in reply to Summing Variables in foreach loop

Are you asking how to get a total of all the results printed by printf "found %d zeros\n", $included_length =~ tr[0][];?

Update: I'll go with that assumption, and that you're looking for an elegant solution, by some subjective definition of elegant. A word of warning; elegance may be in the eye of the beholder. Anyway, here's my stab at it:

use strict; use warnings; no warnings 'once'; use feature 'say'; use List::Util 'reduce'; my $cgs = '10001011101010010101101000010101101011101111010100101010101 +0'; sub substr_at { substr $_[0], $_[1], $_[2]-$_[1]; } sub count_zeros { ( my $string, local $_ ) = @_; substr_at( $string, ( split )[1,2,1] ) =~ tr[0][]; } say reduce { $a += count_zeros($cgs,$b) } 0, <DATA>; __DATA__ junk 5 15 junk 23 59 junk 18 34 junk 10 20 junk 9 19 junk 40 49

Here's how it works:

And the reason I think it's elegant is that it is uncluttered, and seems to flow nicely. At any level, from the low end (substr_at) to the high end (reduce), you can look at what's happening and understand without spending too much time trying to grok the code.

Keep in mind though, any time you're summing anything, there's a loop involved, whether you see it or not. In the code I provided, "reduce" loops over the contents of <DATA>. Internally there are other loops as well, such as the one that the transliteration operator must use to count matches in a string. But even though we know the loops are there, it's nice to work at a level of abstraction where we're not boringly typing out "foreach..."


Dave

Replies are listed 'Best First'.
Re^2: Summing Variables in foreach loop
by AnomalousMonk (Archbishop) on Jan 30, 2014 at 08:56 UTC

    Derived from davido — dunno if it's more elegant or not:

    use strict; use warnings; use List::Util qw(sum); my $cgs = '10001011101010010101101000010101101011101111010100101010101 +0'; print # prints 45 as does davido's solution sum map substr($cgs, $_->[1], $_->[2]-$_->[1]) =~ tr/0//, map [ split ], <DATA> ; __DATA__ junk 5 15 junk 23 59 junk 18 34 junk 10 20 junk 9 19 junk 40 49

    Update: Changed
        map scalar(substr($cgs, $_->[1], $_->[2]-$_->[1]) =~ tr/0//),
    to
        map substr($cgs, $_->[1], $_->[2]-$_->[1]) =~ tr/0//,
    (same result).

Re^2: Summing Variables in foreach loop
by tobyink (Canon) on Jan 30, 2014 at 14:57 UTC

    A more normal way to use reduce would be to use the + operator in there, not +=. Using += could give the impression that the variable $a can be usefully modified within the block.

    say reduce { $a + count_zeros($cgs,$b) } 0, <DATA>;
    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      A even more normal way would be avoid reduce entirely :)
      say sum 0, map count_zeros($cgs,$_), <DATA>;
Re^2: Summing Variables in foreach loop
by ccelt09 (Sexton) on Jan 30, 2014 at 06:30 UTC
    yes that is a better way to say it

      I had thought to use something like this

      my $total_coverage = 0; #looping variable my $interval = "/Users/logancurtis-whitchurch/Desktop/chrX_divisions/" +."$region"."_$filter".".txt"; #specifiecs intervals by region and fil +ter version open (INTERVAL, "<$interval") or die "can't open interval file\n"; foreach ( <INTERVAL> ) { my (undef, $start, $end) = split '\s+', $_; my $subs_length = $end-$start; my $included_length = substr( $cgs, $start, $subs_length ); my $coverage = $included_length =~ tr[0][]; $total_coverage = $total_coverage + $coverage; } print "$total_coverage\n";

      Your approach uses an understanding of the language that I hope to attain some day, quite cool. Thank you!