Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

I don't get map. How would I use map here?

by Plankton (Vicar)
on Jun 18, 2004 at 19:54 UTC ( [id://368044]=perlquestion: print w/replies, xml ) Need Help??

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

I just can't seem to ever understand map. I know the two for loops below could be rewriten with map. Could someone help me out here?
#!/usr/local/bin/perl -w use strict; my %byFile; for (<DATA>) { my ( $size, $name ) = split /\s+/; $byFile{$name} = $size; } for ( keys %byFile ) { print "$_\t=>$byFile{$_}\n"; } __DATA__ 0 5713813 276k CVS_RES 264k Desktop 17k Documes 33k SEARCH
Thanks!
<update>Sorry for not be clearer in the first place, but I do need to use %byFile for other purposes. The script I posted just demostrates some isolated code I have in another script.

Plankton: 1% Evil, 99% Hot Gas.

Replies are listed 'Best First'.
Re: I don't get map. How would I use map here?
by Zaxo (Archbishop) on Jun 18, 2004 at 20:15 UTC

    The first can be written, my %byFile = map { reverse split } <DATA>; That relies on the data being reliable in format.

    The second can be mapped, too, but I'd more likely write it either the way you have it, or else as while (my ($key, $val) = each %byFile) { . . .  }. Here is a mapped version, print map {"$_\t=>$byFile{$_}\n"} keys %byFile; I'd favor the "while each" version because it is more sparing of memory, and the results are not likely needed elsewhere.

    After Compline,
    Zaxo

Re: I don't get map. How would I use map here?
by NetWallah (Canon) on Jun 18, 2004 at 20:00 UTC
    The key thing to understand is that map returns a list.

    If you do not need a list returned, (which is the case in your example),use for.

    Update:Style suggestion:
    Your second loop is better written as

    while (my ($k,$v) = each %byFile ) { print "$k\t=>$v\n"; }
    This is more idiomatic, uses less memory, and is faster than your loop.

    Offense, like beauty, is in the eye of the beholder, and a fantasy.
    By guaranteeing freedom of expression, the First Amendment also guarantees offense.

Re: I don't get map. How would I use map here?
by jeffa (Bishop) on Jun 18, 2004 at 21:12 UTC
Re: I don't get map. How would I use map here?
by duff (Parson) on Jun 18, 2004 at 20:21 UTC

    Here's one way to use map for what you want:

    #!/usr/bin/perl use strict; print map { "$_->[1]\t=>$_->[0]\n" } map { [ split ] } <DATA>; __DATA__ 0 5713813 276k CVS_RES 264k Desktop 17k Documes 33k SEARCH

    But the magic really isn't so much in the map as it is in the use of an anonymous array.

Re: I don't get map. How would I use map here?
by Eimi Metamorphoumai (Deacon) on Jun 18, 2004 at 20:15 UTC
    Personally, I wouldn't use map in either of those places. Definitely not in the second, since it would be evaluating it for side effects only. For the first you could use
    %byFile = map {(split /\s+/)[1,0]} <DATA>;
    with the proviso that it would remove anything already in %byFile. That is, it would take each element from DATA and translate it into two elements, creating a list of pairs to be treated as a hash. But I still don't think this is a great place for map, because it's not as easy to read (and quite a bit more confusing).
Re: I don't get map. How would I use map here?
by Fletch (Bishop) on Jun 18, 2004 at 20:12 UTC

    Use map to transform one list of values into a new list; use for to iterate over a list performing some operations. In both of your cases you're not really generating a new list. The first one could be done as  my %byFile = map { chomp; split( /\s+/, $_, 2 ) } <DATA>, but I'd personally use the for instead. Considering your second loop is a single statement I'd probably write it as print "$_\t=>$byFile{$_}\n" for keys %byFile, but definately not using map.

Re: I don't get map. How would I use map here?
by eric256 (Parson) on Jun 18, 2004 at 20:03 UTC

    Neither realy needs to be a map. However you could make the second one a map like the following:

    map { print "$_\t=>$byFile{$_}\n"; } keys %byFile;

    ___________
    Eric Hodges

      map in void context still rankles me for some reason (even though I understand that perl now has an optimization for it). So I'd write that as one of these:

      print map { "$_\t=>$byFile{$_}\n" } keys %byFile;
      or
      print "$_\t=>$byFile{$_}\n" for keys %byFile; # look Ma! no map! :-)
Re: I don't get map. How would I use map here?
by pbeckingham (Parson) on Jun 18, 2004 at 20:55 UTC

    First I'd reduce your two loops to one:

    while (<DATA>) { print "$2\t=>$1\n" if /^(.*?)\s+(.*?)$/; } __DATA__ 0 5713813 276k CVS_RES 264k Desktop 17k Documes 33k SEARCH
    Then I'd substitute the map for the for:
    map {print "$2\t=>$1\n" if /^(.*?)\s+(.*?)$/} <DATA>; __DATA__ 0 5713813 276k CVS_RES 264k Desktop 17k Documes 33k SEARCH
    As long as you are okay with there being a serious loss in readability, and it smacks of golf.

Re: I don't get map. How would I use map here?
by Chady (Priest) on Jun 19, 2004 at 09:42 UTC

    One OT but related note is the use of for to read from a filehandle.

    I got bitten by that before.

    for will create the list and iterate over it. This means that if <DATA> is a filehandle to a file containing 1Gb of data, for will attempt to create the 1Gb+ list, thus bringing your system to its knees.

    The 'safer' way to do this would be to use a while instead of for because it doesn't create the list.


    He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

    Chady | http://chady.net/
Re: I don't get map. How would I use map here?
by ryantate (Friar) on Jun 18, 2004 at 21:53 UTC

    Not sure if you're looking to replace both loops entirely or whether you need %byFile for other purposes ...

    print map {join("\t=>", reverse split) . "\n"} <DATA>;

    Update: replaced superflous foreach after print

      Update: replaced superflous foreach after print

      You could also remove the superfluous map :-)

      print join ( "\t=>", reverse split ) . "\n", <DATA>;

      Update: Sorry, ignore

        Not without putting it in a different loop:
        print join("\t=>", reverse split), "\n" while <DATA>;

        We're not really tightening our belts, it just feels that way because we're getting fatter.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://368044]
Approved by Corion
Front-paged by pbeckingham
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2024-04-23 19:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found