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

I've got a code snippet below that reads in some data and maps the clip name with the clip number. I used a foreach loop to iterate through the data, split each line then put the data into a hash. I would like to change this foreach loop to map.

my attempt at using map failed as shown below. Ideally I would like something like:

$VAR1 = { 'D:\\Main\\Running a Business\\Euro\\EuroIssues' => 0 'D:\\Main\\Running a Business\\Euro\\EuroIssues' => 1 'D:\\Main\\News\\Business News\\about euro\\Introduction to the Eur +o' => 3
This is the output from the map command, dumped via Data::Dumper
$VAR1 = { '1,D:\\Main\\Running a Business\\Euro\\EuroIssues' => 13, '6,D:\\Main\\News\\Business News\\about euro\\Euro-Intro' => 13, '0,D:\\Main\\mainmenu' => 13, '4,D:\\Main\\News\\Business News\\about euro\\Euro Issues' => 13, '7,D:\\Main\\News\\Business News\\about euro\\whatis emu' => 13, '10,D:\\Main\\News\\Business News\\about euro\\what uk and emu' => 1 +3, '5,D:\\Main\\News\\Business News\\Bugs\\Millenium Bug Menu' => 13, '2,D:\\Main\\News\\Business News\\Main Business News Menu' => 13, '3,D:\\Main\\News\\Business News\\about euro\\Introduction to the Eu +ro' => 13, '9,D:\\Main\\News\\Business News\\about euro\\govt decide' => 13, '8,D:\\Main\\News\\Business News\\about euro\\your question answered +' => 13 };
Here is the code.
use strict; my (%ClipNames,@clips,@DataArray); @DataArray = <DATA>; @clips = grep { /^[0-9]+,[A-Z]:/ } @DataArray; # Extract clip info chomp (@clips); # QUERY: Can this foreach loop be replaced by a map? # Following map line does not work properly. # my %ClipNames = map { $_, $. } @clips; foreach (@clips) # Create hash of clip IDs & clip names. { my @ClipLine = split(/,/,$_); $ClipNames{$ClipLine[0]} = $ClipLine[1]; # Clip ID -> ClipName } use Data::Dumper; $Data::Dumper::Indent = 1; print Dumper(\%ClipNames); exit; __DATA__ 0,D:\Main\mainmenu 1,D:\Main\Running a Business\Euro\EuroIssues 2,D:\Main\News\Business News\Main Business News Menu 3,D:\Main\News\Business News\about euro\Introduction to the Euro 4,D:\Main\News\Business News\about euro\Euro Issues 5,D:\Main\News\Business News\Bugs\Millenium Bug Menu 6,D:\Main\News\Business News\about euro\Euro-Intro 7,D:\Main\News\Business News\about euro\whatis emu 8,D:\Main\News\Business News\about euro\your question answered 9,D:\Main\News\Business News\about euro\govt decide 10,D:\Main\News\Business News\about euro\what uk and emu
thanks for your help!

dmtelf

Replies are listed 'Best First'.
Re: Data to hash via map problem
by davorg (Chancellor) on Sep 06, 2000 at 15:03 UTC

    The map to exactly recreate the effects of your foreach loop would be something like this:

    my %ClipNames = map { (split/,/)[0, 1] } @clips;

    but that doesn't produce what you ask for - the keys and values are the wrong way round. If what you ask for above is what you really want, then you'd need to change round the elements in the array slice like this:

    my %ClipNames = map { (split/,/)[1, 0] } @clips;

    The reason that you're seeing thevalue 13 is that you're using $. after you've read the whole data file, so $. is set to the number of lines in the file (i.e. the line number of the last line).

    You can, of course, combine most of your processing into one line once you've worked out which map you want to use - like this:

    my %ClipNames = map { (split/,/)[0, 1] } grep /^[0-9]+,[A-Z]:/ } <DATA>;
    --
    <http://www.dave.org.uk>

    European Perl Conference - Sept 22/24 2000, ICA, London
    <http://www.yapc.org/Europe/>
Re (tilly) 1: Data to hash via map problem
by tilly (Archbishop) on Sep 06, 2000 at 15:05 UTC
    The following should work like your current line:
    my %clipNames = map {(split /,/, $_)[0,1]} @clips;
    But if you have a lot of clips I should warn you that the foreach loop will be a lot faster than map with current Perls. (This is a bug that should be fixed in the next release.)
      Don't raise so much FUD about map, tilly! It's only slower in the current releases when the output array is larger than the input array.

      One-to-one or one-to-less-than-one mapping is still quite fast: as fast as using a grep (on which the map code was originally based).

      What was improved was the less common but equally useful case of one-to-more-than-one (more outputs than inputs), and that speedup code is in 5.7.0 and soon will be in 5.6.1 (about a month, I'm hearing from P5P).

      -- Randal L. Schwartz, Perl hacker

        And the map under discussion is a one-to-two map, so the big slow-down does apply here.

        There are also plenty of cases where map leads to slower code, not because of map being slow but because of memory requirements or the need to create lots of small data structures.

        map often leads to less error-prone code and that is a strong reason to use it.

                - tye (but my friends call me "Tye")
        You are kidding around, right?

        As tye mentioned, this is exactly the case that hit the slowdown, and who should know better than me...? :-)

        Sheesh, I guess I will have to do something else sometime so you can have more to kid me about!