The map function

M

mynews

Whis is difference between map and for-each?
Why the map function is fast than for-each? <== is it for all case?
 
J

Jürgen Exner

mynews said:
Whis is difference between map and for-each?

They have very little in comon except that both loop over the elements
of a list. map() is a function, foreach is a statement modifier or a
compound (loop) statement.

While sometimes map() can be used to achive similar results as a
foreach, usually that's not a good idea because you create a return
value only to throw it away.
Vice-versa you can use map() to return a completely different list than
its argument while modifying the list of a foreach loop is strongly
discouraged and may lead to very unexpected results.
Also closures are more natural with map().
Why the map function is fast than for-each? <== is it for all case?

It is? That would surprise me, but I haven't run any benchmarks.

jue
 
T

Tad J McClellan

Gerry Ford said:
Jürgen Exner said:
They have very little in comon except that both loop over the elements
of a list. map() is a function, foreach is a statement modifier or a
compound (loop) statement.

While sometimes map() can be used to achive similar results as a
foreach, usually that's not a good idea because you create a return
value only to throw it away.
Vice-versa you can use map() to return a completely different list than
its argument while modifying the list of a foreach loop is strongly
discouraged and may lead to very unexpected results.
Also closures are more natural with map().


It is? That would surprise me, but I haven't run any benchmarks.

I think of foreach as a loop and map as a function like this:
map ($_->[$subject_offset].' from '.$_->[$from_offset], @xover)


You didn't show where the return value from map() is going, I'll assume:

@list = map ($_->[$subject_offset]...

They don't seem like comparables to me.


@list = ();
foreach ( @xover ) { # untested
push @list, $_->[$subject_offset].' from '.$_->[$from_offset];
}


The contents of @list are the same either way.
 
N

nolo contendere

They have very little in comon except that both loop over the elements
of a list.  map() is a function, foreach is a statement modifier or a
compound (loop) statement.

While sometimes map() can be used to achive similar results as a
foreach, usually that's not a good idea because you create a return
value only to throw it away.
Is this still true? I thought map in void context was optimized.
 
U

Uri Guttman

GF> Maybe we can use this script to compare and contrast:
GF> sub read_killrc {
GF> open(FILE, "<$killrc") and do {
GF> @filter = ();

not needed in the map version

GF> foreach (<FILE>) {
GF> chomp; length or next; /^#/o and next;
GF> my $pat; eval '$pat = qr/$_/' or do {prompt $@; next};
GF> push @filter, $pat;
GF> }
GF> close(FILE);

GF> What would this syntax look like with a map function?

untested:

return unless open(my $file, "<$killrc") ;
return map {
/^([^#]+)#?$/ &&
eval{ qr/$1/} || prompt $@, ()
} <$file> ;

maybe the return failure value should be grepped out but that is a minor
style change.

map makes tight loops like that much cleaner. they remove the collecting
array and its push and uses less perl which generally makes it faster
(in the right conditions, especially with shorter arrays)

map is such a basic concept i wonder why it seems to be a stumbling
block for so many newbies. year after year we get the same map
queries. what use is it? how do i convert loops to maps? is it faster or
slower? void map is ok? some are in the faq but there must be something
missing if this perl learning speed bump always seems to hit so many.

uri
 
C

Charlton Wilbur

UG> map is such a basic concept i wonder why it seems to be a
UG> stumbling block for so many newbies. year after year we get
UG> the same map queries.

Because most of the time the newbies have run into the other basic
concepts elsewhere -- for loops, if/then, subroutines, etc., even
object orientation -- but it's very likely that Perl is their first
exposure to map and functional programming.

Charlton
 
J

Jürgen Exner

Uri Guttman said:
map is such a basic concept i wonder why it seems to be a stumbling
block for so many newbies.

Actually map() is not as trivial, because it is a higher order function,
i.e. a function that takes a function (or code block) as argument.
I've seen this again and again when we tought functional programming
that there are otherwise smart students, who simply couldn't grasp the
concept that a function can be data (i.e. argument to another function),
too.
And considering that not many students are tought functional programming
at all and that most well-known languages don't have higher-order
functions at all it is not surprising that map() is a speed bump for
many.
Another nice example is sort(). I wonder how many implemented their own
sorting algorithm because they couldn't figure out how to write the
comparision function for non-trivial sorts.

jue
 
U

Uri Guttman

JE> Actually map() is not as trivial, because it is a higher order
JE> function, i.e. a function that takes a function (or code block) as
JE> argument. I've seen this again and again when we tought
JE> functional programming that there are otherwise smart students,
JE> who simply couldn't grasp the concept that a function can be data
JE> (i.e. argument to another function), too.

coming from assembler where i passed around pointers to code all the
time and similarly i did that in c and i knew list, yes, functional
programming is a core thing with me. but if you teach references first
including dispatch tables, then shifting to functional programming and
map should be easy. i do training too and i don't find it hard to teach
map/grep but they do need some handholding.

JE> Another nice example is sort(). I wonder how many implemented
JE> their own sorting algorithm because they couldn't figure out how
JE> to write the comparision function for non-trivial sorts.

that is one reason i wrote sort::maker! :)

uri
 
U

Uri Guttman

GF> "Uri Guttman said:
untested:

return unless open(my $file, "<$killrc") ;
return map {
/^([^#]+)#?$/ &&
eval{ qr/$1/} || prompt $@, ()
} <$file> ;
GF> I tried both versions of this without any success whatsoever:

how about showing your output?

GF> #!/usr/bin/perl -w

use warnings is better than -w
GF> use strict;

GF> my $killrc = "sample.killrc";
GF> my @filter;
GF> my @list1 = qw( Mon Tu Wed);

where did that come from?

GF> open(FILE, "<$killrc") and do {
GF> @filter = ();
GF> foreach (<FILE>) {
GF> chomp; length or next; /^#/o and next;
GF> my $pat; eval '$pat = qr/$_/' or do {prompt $@; next};
GF> push @filter, $pat;
GF> }
GF> close(FILE);

GF> }
GF> print @filter;
GF> print @list1;

and the results?

GF> # perl mats5.pl 2>text50.txt >text51.txt

why the redirect of stderr? there is no stderr output. and what is in
the prompt sub?

GF> __END__

GF> #!/usr/bin/perl -w

GF> use strict;

GF> my $killrc = "sample.killrc";

my return calls IMPLY A SUB is surrounding it. of course it won't work
as shown. jeez, i can't hold your hand and also blow your nose. think
about the code and don't just copy/run it.

GF> return unless open(my $file, "<$killrc") ;
GF> return map {
GF> /^([^#]+)#?$/ &&
GF> eval{ qr/$1/} || prompt $@, ()
GF> } <$file> ;


GF> # perl mats4.pl 2>text50.txt >text51.txt
GF> __END__

GF> Perl is so idiomatic, it makes me scream. The syntax for the print
GF> statement is:
GF> print LIST
GF> How this doesn't fit the bill is beyond me.
GF> print @list1;

huh? show a complete runnable example of why you think that doesn't
work. my guess is that @list1 has no newlines and so doesn't get printed
until the program ends. this is a well know buffering issue and isn't a
bug in perl.

GF> I find no example of printing a list in the camel book. It does have
GF> print reverse sort map (1c) keys %hash;

and in the FAQ? on cpan? the camel book is just a book. it can't have
every possible example you want. and also note that the perl docs are
the actually final language description, not the camel books.

uri
 
J

Jürgen Exner

[shortened to key lines]
my @list1 = qw( Mon Tu Wed);
print @list1;

Perl is so idiomatic, it makes me scream. The syntax for the print
statement is:
print LIST
How this doesn't fit the bill is beyond me.
print @list1;

Huh??? What do you mean?
That print statement prints exactly the elements of that list. What did
you expect it to print?

jue
 
U

Uri Guttman

JE> Huh??? What do you mean?
JE> That print statement prints exactly the elements of that list. What did
JE> you expect it to print?

see my recent reply to this. my bet is it is the typical missing
newline/stdout buffering issue. note that @list1 has no newlines nor
does the built up array. and he never showed the output, just how he
collected it.

uri
 
J

Jim Cochrane

I simply can't see what's wrong with this:
#!/usr/bin/perl -w

use strict;

my $killrc = "sample.killrc";
my @filter;
my @list1 = qw( Mon Tu Wed);
open(FILE, "<$killrc") and do {
@filter = ();
foreach (<FILE>) {
chomp; length or next; /^#/o and next;
my $pat; eval '$pat = qr/$_/' or do {prompt $@; next};
push @filter, $pat;
}
close(FILE);

Change:
}

to:
};

(i.e., missing a ';' - and your code could be formatted better)
print @filter;
print @list1;

# perl mats5.pl 2>text50.txt >text51.txt
__END__

Perl.exe says:
syntax error at mats5.pl line 18, near "print"

The compiler was pointing pretty much right at the problem.


--
 
J

Jürgen Exner

Perl.exe says:
syntax error at mats5.pl line 18, near "print"
Execution of mats5.pl aborted due to compilation errors.

Man, dude!!! How are we supposed to guess??? You could have told us
that your beef is not with the functionality of print() but with a
syntax error in that program! Thank you very much for throwing around
red herrings.
I simply can't see what's wrong with this:

You got some 'intesting' ways of doing things. I know, there is more
than one way to do things, but your style is kind of pushing it
#!/usr/bin/perl -w

Better to use
use warnings;
use strict;

my $killrc = "sample.killrc";
my @filter;
my @list1 = qw( Mon Tu Wed);
open(FILE, "<$killrc") and do {

The more standard way would be
open (FILE, "<", $killrc) or die ("Cannot open $killrc: $!";
@filter = ();
foreach (<FILE>) {
chomp; length or next; /^#/o and next;

Probably it is just me, but I have an strong adversion against mixing
expressions and flow controll in such a way. I would write it as
next unless length;
next if /^#/o;
IMNSHO this is _much_ easier to read and understand.
my $pat; eval '$pat = qr/$_/' or do {prompt $@; next};

And this is where your unorthodox style bites you. Did you really mean
to eval() the whole rest of the line? Because the argument to eval is
indeed
qr/$_/' or do {prompt $@; next}
I suppose you meant to eval only the
qr/$_/'
Solution: enclose the argument to eval in paranthesis and the mysterious
syntax error is gone:

my $pat; eval ('$pat = qr/$_/') or do {prompt $@; next};

However, I wonder what you are trying to achive by using eval in the
first place. I don't see any need for it.
push @filter, $pat;
}
close(FILE);

}
print @filter;
print @list1;

jue
 
U

Uri Guttman

JE> And this is where your unorthodox style bites you. Did you really mean
JE> to eval() the whole rest of the line? Because the argument to eval is
JE> indeed
JE> qr/$_/' or do {prompt $@; next}
JE> I suppose you meant to eval only the
JE> qr/$_/'

or has a very low precedence and that should parse as he intended. sure
it is bad style in other ways but or will bind lower than a call to eval
and its single EXPR.

JE> However, I wonder what you are trying to achive by using eval in the
JE> first place. I don't see any need for it.

i said that before and showed how to just use the qr// directly in my
map example. which he then didn't wrap in a sub as i only showed the map
call.

uri
 
J

John W. Krahn

Jürgen Exner said:
Man, dude!!! How are we supposed to guess??? You could have told us
that your beef is not with the functionality of print() but with a
syntax error in that program! Thank you very much for throwing around
red herrings.


You got some 'intesting' ways of doing things. I know, there is more
than one way to do things, but your style is kind of pushing it


Better to use
use warnings;

The more standard way would be
open (FILE, "<", $killrc) or die ("Cannot open $killrc: $!";


Probably it is just me, but I have an strong adversion against mixing
expressions and flow controll in such a way. I would write it as
next unless length;
next if /^#/o;

Also the /o option is superfluous there as there are no variables in the
pattern.

IMNSHO this is _much_ easier to read and understand.


And this is where your unorthodox style bites you. Did you really mean
to eval() the whole rest of the line? Because the argument to eval is
indeed
qr/$_/' or do {prompt $@; next}

No it isn't:

$ perl -MO=Deparse -e'my $pat; eval q[$pat = qr/$_/] or do {prompt $@;
next};'
my $pat;
unless (eval '$pat = qr/$_/') {
do {
$@->prompt;
next;
};
}
-e syntax OK

I suppose you meant to eval only the
qr/$_/'

It looks like he meant to eval the string '$pat = qr/$_/'.

Solution: enclose the argument to eval in paranthesis and the mysterious
syntax error is gone:

The syntax error is not related at all to this statement. Jim Cochrane
posted the correct solution. The problem is that the do {} block
following the open() does not end with a semicolon.

my $pat; eval ('$pat = qr/$_/') or do {prompt $@; next};

However, I wonder what you are trying to achive by using eval in the
first place. I don't see any need for it.
^^^^
Missing ; for do {} block.



John
 
U

Uri Guttman

JWK> The syntax error is not related at all to this statement. Jim Cochrane
JWK> posted the correct solution. The problem is that the do {} block
JWK> following the open() does not end with a semicolon.
JWK> ^^^^
JWK> Missing ; for do {} block.

another reason to avoid do blocks. in a 10k line system i wrote i found
2 uses of do blocks. and in the OP's case the normal open or die/return
is of course the better style. having a large do block after an or is
just insane. an if/then would do the same and be much more normal and
readable if you couldn't use statement modifiers or such.

uri
 
N

nolo contendere

Thanks, Jim.  Missing semicolons were the culprit:

#!/usr/bin/perl -w

use strict;
use warnings;

my $killrc = "sample.killrc";
my @filter;
my @list1 = qw( Mon Tu Wed);
    open(FILE, "<$killrc") and do {
        @filter = ();
        foreach (<FILE>) {
            chomp; length or next; /^#/o and next;
            my $pat; eval '$pat = qr/$_/' or do {prompt $@; next};
            push @filter, $pat;
        };
        close(FILE);

};

print @filter;
print @list1;

#  perl mats5.pl 2>text50.txt >text51.txt
__END__
#end script begin output

(?-xism:^From:.*<[email protected]>)(?-xism:^Subject:.*MONEY)(?-xism:^Message-ID:.*googlegroups)MonTuWed

#end output show sample.killrc
^From:.*<[email protected]>
^Subject:.*MONEY
^Message-ID:.*googlegroups

Any ideas where the ?-xism is coming from?

those are from the compiled regex. check out the effect of qr// on a
simple regex by printing it.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top