grep example's use of $_ confusing me.

Discussion in 'Perl Misc' started by Justin C, Oct 29, 2010.

  1. Justin C

    Justin C Guest

    I'm reading The Alpaca (Intermediate Perl - yeah, I know, do I *really*
    think I'm smart enough to be there yet?) and in Chapter 6 I find the
    following example:

    my @input_numbers = (1, 2, 4, 8, 16, 32, 64);
    my @indices_of_odd_digit_sums = grep {
    my $number = $input_numbers[$_];
    my $sum;
    $sum += $_ for split //, $number;
    $sum % 2;
    } 0..$#input_numbers;

    What has happened to $_ ? In line three I understand that it is one of
    the indices of @input_numbers, but in line 5 it has become each of the
    digits of @input_numbers. I'm just getting used to map and grep, and
    throwing that in there has been a bit confusing. I can see what has
    happened, but am having difficulty reconciling that with use of $_ in
    grep and map blocks. Is the first $_ clobbered, or is it still there
    after the 5th line? ... hmmm, yes it is... not it isn't it's been
    clobbered, it's... no, I was right the first time! (it's been a long
    week). So, is line 5 a naked block with it's own $_? How do I identify,
    in other grep/map blocks, which $_ is $_?!

    Justin.

    --
    Justin C, by the sea.
     
    Justin C, Oct 29, 2010
    #1
    1. Advertising

  2. Justin C

    Jim Gibson Guest

    In article <>, Justin C
    <> wrote:

    > I'm reading The Alpaca (Intermediate Perl - yeah, I know, do I *really*
    > think I'm smart enough to be there yet?) and in Chapter 6 I find the
    > following example:
    >
    > my @input_numbers = (1, 2, 4, 8, 16, 32, 64);
    > my @indices_of_odd_digit_sums = grep {
    > my $number = $input_numbers[$_];
    > my $sum;
    > $sum += $_ for split //, $number;
    > $sum % 2;
    > } 0..$#input_numbers;
    >
    > What has happened to $_ ? In line three I understand that it is one of
    > the indices of @input_numbers, but in line 5 it has become each of the
    > digits of @input_numbers.


    The 'for' in line 5 is a statement modifier. Search for 'Statement
    Modifiers' in perldoc perlsyn. Line 5 is equivalent to:

    foreach ( split //, $number ) {
    $sum += $_;
    }

    Further on in 'perldoc perlsyn' we read that:

    "Foreach Loops

    The "foreach" loop iterates over a normal list value and sets the
    variable VAR to be each element of the list in turn. If the variable
    is preceded with the keyword "my", then it is lexically scoped, and is
    therefore visible only within the loop. Otherwise, the variable is
    implicitly local to the loop and regains its former value upon exiting
    the loop. If the variable was previously declared with "my", it uses
    that variable instead of the global one, but it's still localized to
    the loop. This implicit localisation occurs only in a "foreach" loop."

    Thus, $_ is localized in line 5 and regains its previous value at line
    6.

    Note also that the original value of $_ at entering the grep block is
    only used once in the first line of the block, so it doesn't really
    matter whether $_ is clobbered by the for modifier. Programming that
    does not depend upon little-known behavior is usually a "good thing".

    > I'm just getting used to map and grep, and
    > throwing that in there has been a bit confusing. I can see what has
    > happened, but am having difficulty reconciling that with use of $_ in
    > grep and map blocks. Is the first $_ clobbered, or is it still there
    > after the 5th line? ... hmmm, yes it is... not it isn't it's been
    > clobbered, it's... no, I was right the first time! (it's been a long
    > week). So, is line 5 a naked block with it's own $_? How do I identify,
    > in other grep/map blocks, which $_ is $_?!


    If you want to know what value is in $_ at any point in your program,
    run it with a debugger or add some print statements:

    #!/usr/bin/perl

    use strict;
    use warnings;

    my @input_numbers = (1, 2, 4, 8, 16, 32, 64);
    my @indices_of_odd_digit_sums = grep {
    print "1: \$_=$_\n";
    my $number = $input_numbers[$_];
    my $sum;
    $sum += $_ for split //, $number;
    print "2: \$_=$_\n";
    $sum % 2;
    } 0..$#input_numbers;

    print "Indices of odd digit sums: ", join(", ",
    @indices_of_odd_digit_sums),
    "\n";

    __OUTPUT__

    1: $_=0
    2: $_=0
    1: $_=1
    2: $_=1
    1: $_=2
    2: $_=2
    1: $_=3
    2: $_=3
    1: $_=4
    2: $_=4
    1: $_=5
    2: $_=5
    1: $_=6
    2: $_=6
    Indices of odd digit sums: 0, 4, 5

    --
    Jim Gibson
     
    Jim Gibson, Oct 29, 2010
    #2
    1. Advertising

  3. Justin C

    Justin C Guest

    On 2010-10-29, Justin C <> wrote:
    > I'm reading The Alpaca (Intermediate Perl - yeah, I know, do I *really*
    > think I'm smart enough to be there yet?) and in Chapter 6 I find the
    > following example:


    Thanks, Tad and Jim. Things are clearer now.

    Justin.

    --
    Justin C, by the sea.
     
    Justin C, Nov 1, 2010
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Gerard Brunick
    Replies:
    0
    Views:
    270
    Gerard Brunick
    Mar 5, 2008
  2. Matthew Wilson

    How should I use grep from python?

    Matthew Wilson, May 7, 2009, in forum: Python
    Replies:
    5
    Views:
    2,208
    Marco Mariani
    May 7, 2009
  3. Mark Wilson
    Replies:
    2
    Views:
    117
    Jason Creighton
    Sep 17, 2003
  4. Matt
    Replies:
    6
    Views:
    134
    Justin Collins
    Jan 10, 2010
  5. perlmbk
    Replies:
    3
    Views:
    566
Loading...

Share This Page