Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

foreach/map equivalency

by rob_au (Abbot)
on Nov 10, 2001 at 21:36 UTC ( [id://124572]=perlquestion: print w/replies, xml ) Need Help??

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

In trying to cut my code to a minimum, I have come up against a stumbling point in replacing a perfunc:foreach loop with a perlfunc:map statement - This stumbling point revolves around the following code:

#!/usr/bin/perl -Tw use CGI; use XML::Simple; use strict; my $xs = XML::Simple->new; my $xml = eval { $xs->XMLin('../xml/users.xml') }; die $@ if ($@); my $cgi = CGI->new; my @foreach; foreach (@{%{$xml}->{'user'}}) { push (@foreach, $_) if $_->{'username'} eq $cgi->param('username') +; }; my @map = map { $_ if $_->{'username'} eq $cgi->param('username'); } @ +{%{$xml}->{'user'}};

To my mind, the foreach and map segments of code are equivalent - Herein lies the problem I suspect. They are not.

If indeed, these pieces of code are equivalent, one could rightly expect the output arrays of each code segment to be the same for a given input. This is not occurring - Instead, the array output from the map code segment comprises of a large number of null values (one for each non-matching field) and the single result expected (and returned from the foreach code segment).

And so my question is ... What am I doing wrong here? Is there a way to have map return no value (compared with null value) into the output array if a given condition on the input scalar is not met?

 

Ooohhh, Rob no beer function well without!

Replies are listed 'Best First'.
Re: foreach/map equivalency
by wog (Curate) on Nov 10, 2001 at 21:48 UTC
    To return no value from a map, you're probably going to need to explictly return a null list, ():

    my @map = map { $_->{'username'} eq $cgi->param('username') ? $_ : () } @{%{$x +ml}->{'user'}};

    However this is better written with grep:

    my @grep = grep { $_->{'username'} eq $cgi->param('username') } @{%{$x +ml}->{'user'}};
Re: foreach/map equivalency
by Masem (Monsignor) on Nov 10, 2001 at 21:50 UTC
    Wouldn't grep be what you're after here?
    my @users = grep { $_->{'username'} eq $cgi->param('username') @{%{$xm +l}->{'user'}};

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    "I can see my house from here!"
    It's not what you know, but knowing how to find it if you don't know that's important

Re: foreach/map equivalency
by ChemBoy (Priest) on Nov 10, 2001 at 21:53 UTC

    Is there a way to have map return no value (compared with null value) into the output array if a given condition on the input scalar is not met?
    Well, yes. I think $foo eq $bar ? $_ : () would do it (among other possibilities). But why not just use grep instead?
    my @grepped = grep {$_->{'username'} eq $cgi->param('username')} @{ %{$xml}->{'user'} };



    If God had meant us to fly, he would *never* have given us the railroads.
        --Michael Flanders

Re: foreach/map equivalency
by gloryhack (Deacon) on Nov 10, 2001 at 21:48 UTC

    map iterates over the array, as you suspected it would... in the case you provide, you use a push in the first example, but don't in the second. So, you're seeing the default, Larry-thought-it-wise behavior in the second.

    Rewrite that map statement so that it, too, uses push, and it oughta do what you expected.

      This is wrong. map produces a list without having to perform any stack or array operations. That's why it's not spelled for or foreach. That's also why rob_au is getting null values.

      Update: That is to say, map handles the list construction for you, and assigning the results to some sort of variable handles the list assignment. Under the covers, it's free to use whichever linked list or stack operations it prefers.

        Updated in response to upstream update...

        So, then, if it does, or can, iterate over the source list in order to create the destination list, how is it that I am wrong?

        I'm not trying to be right, I'm trying to gain an understanding of why I'm not.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (3)
As of 2024-04-24 05:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found