lightoverhead has asked for the wisdom of the Perl Monks concerning the following question:

if I want to print the line number of a file I did this:

while(<>){ print "$.\n" }

it works fine. However, if I try to use "map":

map{print "$.\n"}<>;

it can only print the last(or total) line number.

Does anyone know why this happens? How should I (or Can I)use "map" or "grep" to get or the line number of a file using "$."?

Thanks.

Replies are listed 'Best First'.
Re: Different behaviors between "while" and "map"
by friedo (Prior) on Dec 06, 2008 at 00:08 UTC

    The reason this happens is because the while loop is designed to operate on <> like an iterator. Thus, it reads one line at a time until it can't read anymore.

    By contrast, using <> as the list for your map block reads the entire file in all at once, incrementing $. along the way. The entire file then gets passed to your map block as one big list, and by this time, $. has already been incremented to the number of the last line, so the same $. gets printed each time through the map block.

      Just to expand a little on this: map, grep, foreach and most while constructs all work on perl's concept of lists.

      while (<SOME_FILE_HANDLE>)
      is special. it does not act like any other iteration construct, not even like any other while() construct. It explicitly iterates over each record ("line") one by one instead of converting the whole file to a list first.

        It helps to know that the loop is expanded to:

        while ($_ = <SOME_FILE_HANDLE>){ ... }

        This shows that <...> is nothing more than a loop condition: the loop body is executed immediately after each evaluation of the <...> operator. This is how a while loop works.

Re: Different behaviors between "while" and "map"
by chromatic (Archbishop) on Dec 06, 2008 at 00:58 UTC

    You shouldn't use map or grep for this purpose. map transforms one list into another, applying a given function to each element in turn. grep filters a list by applying a given function which returns a boolean value to each element in turn.

    You're relying on side-effects of their implementation, and that'll cause you grief.

Re: Different behaviors between "while" and "map"
by JavaFan (Canon) on Dec 06, 2008 at 00:50 UTC
    Does anyone know why this happens?
    Context. The guard of a while is in scalar context, all argument following the block of map are in list context. And the diamond operator reads one line in scalar context, and all the lines in list context.
    How should I (or Can I)use "map" or "grep" to get or the line number of a file using "$."?
    Count the lines yourself:
    my $count = $. - 1; map {++$count; your statements here} <>;