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



Question: Both of these methods seem to be the same. The map method is, of course, shorter...Why doesn't it work is my question.


here is my map strategy:
$MAIL_ROOT = '/var/mail'; my @users = (map s/$MAIL_ROOT// , `find $MAIL_ROOT -type d -maxdepth +1`);
and here is the foreach that does what I want, I want to do a map instead of this foreach.

my @users = `find $MAIL_ROOT -type d -maxdepth 1`; foreach (@users) { chomp; s/$MAIL_ROOT//; print $_ . "\n" unless $_ eq ''; }
is there some reason map is not working correctly?

-----------------------------------------------Update --------------------------------------------

What it might be perhaps...

$_ is undefined because its finding $_ for @users on that same line??? Is this my problem? In other words, we make sure to return $_ and we're in good shape.


-------------------Solution---------------
Ah, I see, I was assigning the value to s/// and mapping incorrectly: correct way:
chomp( my @users = map { s/$MAIL_ROOT//; $_ } `find $MAIL_ROOT -type d + -maxdepth 1` );
from jwkrahn is prob the least effort for a fix and the one i went with :)

Replies are listed 'Best First'.
Re: using map to replace text without using a foreach....
by ikegami (Patriarch) on Aug 17, 2006 at 19:57 UTC

    Check up on the return value of s///. In this case, your s/// always returns 1 (the number of substititions made in that iteration). map takes all those 1s and assigns them to @users. You need to return the changed value to map.

    Also, your usage of map clobbers the value passed to map. True, it doesn't matter in this instance, but it's a bad habit.

    my @users = map { my $s = $_; # Protect the caller. chomp($s); $s =~ s/^\Q$MAIL_ROOT//; $s } `find ...`; # Return the changed value.

    Both List::MoreUtils and Algorithm::Loops provide a function that does this magic for you.

    use List::MoreUtils qw( apply ); my @users = apply { chomp; s/^\Q$MAIL_ROOT//; } `find ...`;
    use Algorithm::Loops qw( Filter ); my @users = Filter { chomp; s/^\Q$MAIL_ROOT//; } `find ...`;

    Update: I fixed your regexp.

Re: using map to replace text without using a foreach....
by jwkrahn (Abbot) on Aug 17, 2006 at 20:25 UTC
    map returns the result of its expression and s/// returns either TRUE or FALSE so your array is receiving these true or false values. You need to return $_ after s/// has modified it:
    chomp( my @users = map { s/$MAIL_ROOT//; $_ } `find $MAIL_ROOT -type d + -maxdepth 1` );
    However what you really should be doing is:
    $MAIL_ROOT = '/var/mail'; opendir my $dh, $MAIL_ROOT or die "Cannot open '$MAIL_ROOT' $!"; my @users = grep -d && !/\A\.\.?\z/, readdir $dh; closedir $dh;