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

perldoc says grep returns "aliases" into the original list and the list can be modified through the grep result.
so for the below
@l = ( "a", "b", "c" ); @m = grep /a/, @l; $m[0] = "z"; print @l;
I expected to get "zbc", but no, it's "abc". Where do I go wrong?
bless you for the alms!

Replies are listed 'Best First'.
Re: modify list through grep
by Sidhekin (Priest) on Nov 26, 2006 at 15:30 UTC

    grep returns aliases, but assignment (to @m) makes copies. You can not modify the grep results directly though, so you need to do something like take a reference, pass it to a (naughty) sub, or make a modifiable alias in order to modify the alias, and not just a copy thereof:

    @l = ( "a", "b", "c" ); $_ = "z" for grep /a/, @l; print @l;

    Prints "zbc".

    print "Just another Perl ${\(trickster and hacker)},"
    The Sidhekin proves Sidhe did it!

Re: modify list through grep
by mickeyn (Priest) on Nov 26, 2006 at 16:01 UTC
    the "aliases" are relevant when you work on a list returned by grep and not on an array that was created using this list.
    (unless, of course the original array contained references which will still refer to the same vars/arrays/hashes)

    example (here map works on the list returned by grep before it's assigned to an array):

    @l = ( "a", "b", "c" ); @m = map {s/a/z/} grep /a/, @l; print @l;
    will print "zbc"

    Enjoy,
    -- Mickey

Re: modify list through grep
by calin (Deacon) on Nov 26, 2006 at 16:07 UTC
    #!/usr/bin/perl # Yo, I'll tell you what I want, what I really really want, # So tell me what you want, what you really really want, # I'll tell you what I want, what I really really want, # So tell me what you want, what you really really want, # I wanna, I wanna, I wanna, I wanna, # I wanna really really really wanna zigazig ha. @l = ( "a", "b", "c" ); *m = &{sub {\@_}} (grep /a/, @l); $m[0] = "z"; print "@l\n";

      I was excited by your answer at first because I thought it was that trick I saw for making aliases, and which I can never remember. ;-)

      But then I realized that you're using a glob, which means you could simply write

      @l = ( "a", "b", "c" ); *m = \@l; $m[0] = "z"; print "@l\n";
      We're building the house of the future together.

        Yes, you're right. My reply was a bit tongue-in-cheek - the OP asked why his grep aliasing example "didn't work" and I resolved to beat it into submission ;)

        There's a slight difference though. *m = \@l; aliases the entire array object. The sub {\@_} trick creates a new array object containing scalar elements which are aliased to memberes in @l matching /a/ (in OP's example it contains only one element aliased to the first element in @l - "a").

Re: modify list through grep
by parv (Parson) on Nov 26, 2006 at 23:26 UTC

    What, nobody remembers grep in grep BLOCK LIST usage?!

    @l = qw( a b c ); # '@m' just as well be '()' unless used later, but then I personally # would be doing C</a/ and $_ = 'z' for @l;>. @m = grep { /a/ and $_ = 'z' } @l; print @l;

    And a different take on reply from Sidhekin ...

    /a/ and $_ = 'z' for @l;

    ~Nov 26 2006, 7p US-EDT: Changed '@p' to '@l'.

Re: modify list through grep
by GrandFather (Saint) on Nov 26, 2006 at 21:44 UTC

    If an array of references suffices then:

    use strict; use warnings; my @l = ( "a", "b", "c" ); my @m = map {\$_} grep /a/, @l; ${$m[0]} = "z"; print @l;

    seems to do what you want:

    zbc

    DWIM is Perl's answer to Gödel