Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

map return to array reference

by silent11 (Vicar)
on Jan 24, 2007 at 16:53 UTC ( [id://596282]=perlquestion: print w/replies, xml ) Need Help??

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

Below is the code in question:
my $files_to_send = map {"$stage/$_.pdf"} @{$self->_getGood()}; print map {"$_\n"} @{$files_to_send};
which returns
Can't use string ("6") as an ARRAY ref while "strict refs" in use at M +oduleName.pm line 136.
I have a sub _getGood() that collects the *good* files I want to process/send in my script. This sub returns an array:
sub _getGood { my ($self,@args) = @_; print "_getGood()", Dumper $self->{_good}; return @{$self->{_good}}; }
I have the Dumper in there for good measure, just to see that I am indeed returning what I want return, an array. The Dumper output prints the following:
$VAR1 = [ 'C21622241', 'C21594007', 'C21619147', 'C21572375', 'C21611603', 'C21617783' ];
At one point in time a variation of this was working, now it's not and I don't see the problem. Besides assigning map to a scalar, I can't see what is amis. I even went so far as to declare $files_to_send = []; like so, and I still get the same results.

ideas? I can get this to work by assigning to an array as opposed to a reference, but that would require extra lines of code :)



-silent11
Spread Firefox

Replies are listed 'Best First'.
Re: map return to array reference
by ikegami (Patriarch) on Jan 24, 2007 at 17:05 UTC
    • Your deref $self->_getGood() twice, but the dump shows it's just a reference to an array of strings.
    • Your map returns a list of file names, but you assign it to a scalar. That sets $files_to_send to 6, the number of file names.
      Your map would return a list of file names, but you assign the result to a scalar. This causes map to return 6, the number of file names.
    sub _getGood { my ($self,@args) = @_; print "_getGood()", Dumper $self->{_good}; # Returns a list of of 'Cxxxx' codes. return @{$self->{_good}}; } my @files_to_send = map {"$stage/$_.pdf"} $self->_getGood(); print map {"$_\n"} @files_to_send;

    Update: The word "twice" was missing.
    Update: Adjusted the wording for clarity in response to merlyn's reply.

      Your map returns a list of file names, but you assign it to a scalar.
      That's not technically possible. The map is not returning a list, if it's being used in a scalar context. It just happens that if a map is used in a scalar context, it returns the number of items it would have created had it been used as a list. But it just as easily could return the day of the year instead (although not quite as useful).

      I know it may not sound like that's an important difference, but it's really important to understand that you don't ever get a list in a scalar context: in a scalar context, you get whatever the operation is defined to do in a scalar context instead. See On Scalar Context for more details.

        merlyn,
        It just happens that if a map is used in a scalar context, it returns the number of items it would have created had it been used as a list. But it just as easily could return the day of the year instead (although not quite as useful).

        Perl 5 uses documentation to explain the implementation so saying "it is documented to return the number of elements in scalar context so it can't just as easily return the day of year instead" doesn't hold much water. Fortunately, Perl 6 is intended to have a complete specification allowing for any number of implementations. This has nothing to do with the issue I wanted to make though.

        Your wording to me implies that map doesn't actually create the elements it counts. The docs say "In scalar context, returns the total number of elements so generated." which implies to me they are created. I know that there could be an optimization not to actually build up the return list such as happens when map is called in a void context with recent versions. If indeed it is as you say, a doc patch should be submitted to clarify.

        Cheers - L~R

Re: map return to array reference
by liverpole (Monsignor) on Jan 24, 2007 at 17:05 UTC
    Hi silent11,

    Since you're assigning to an array reference (my $files_to_send = ...), you should enclose the results of the map in [ ... ]:

    my $files_to_send = [ map {"$stage/$_.pdf"} @{$self->_getGood()} ];

    Otherwise, you're assigning to the count of the items in the array (using the array in scalar context).

    Oh, and you could also simplify @{$files_to_send} to just @$files_to_send.  In fact, if you don't care about printing newlines, you might make it really simple:

    print "@$files_to_send\n";

    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: map return to array reference
by Ieronim (Friar) on Jan 24, 2007 at 17:06 UTC
    Just enclose your map in square brackets to create an array reference.
    my $files_to_send = [map {"$stage/$_.pdf"} @{$self->_getGood()}];
    Look at the following example:
    my @ary = qw/a b c d/; my $var = @ary; # $var is 4; @ary is interpreted in scalar context my $var1 = [@ary]; #$var is ['a','b','c','d']

         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
Re: map return to array reference
by kyle (Abbot) on Jan 24, 2007 at 17:09 UTC

    Your map is returning a list (Update Hmmm, maybe not so much). If you want a reference to an array containing that list, wrap it in square brackets:

    my $files_to_send = [ map {"$stage/$_.pdf"} @{$self->_getGood()} ];

    The reason you get Can't use string ("6") as an ARRAY ref is that the array returned by map, in a scalar context, is turned into the cardinality of the array, so $files_to_send gets the value 6.

    I even went so far as to declare $files_to_send = []; like so, and I still get the same results.

    This is the part that I don't understand. Setting $files_to_send to a reference to an empty array should give you no output in the code you have above. It really gives the same error, or it fails a different way?

Re: map return to array reference
by johngg (Canon) on Jan 24, 2007 at 17:06 UTC
    The string "6" is a good clue, since your Dumper output shows 6 files. $self->_getGood() returns an array so there's no need to wrap it in @{...}. Try

    my $files_to_send = map {"$stage/$_.pdf"} $self->_getGood();

    Cheers,

    JohnGG

    Update: Doh! My eyes saw $files_to_send, my brain translated to @files_to_send. You could change $self->_getGood() to return the array reference instead, return $self->{_good};

Re: map return to array reference
by davorg (Chancellor) on Jan 24, 2007 at 17:06 UTC
    @{$self->_getGood()}

    If $self->_getGood returns an array (or, indeed, a list) then there's no need to dereference it again.

    I assume that '6' is the first item in the returned list.

    my $files_to_send = map {"$stage/$_.pdf"} $self->_getGood();

    But as you hint that you already know, you shouldn't be assigning that to a scalar, so you probably want:

    my $files_to_send = [ map {"$stage/$_.pdf"} $self->_getGood() ];

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-04-18 00:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found