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

This really isn't a homework problem. Honest.

In the following:

#!/bin/env perl my %hash = (one => 1, two => 1, three => 1); map { $hash{$_} = 0 } ('two', 'three');
$hash{one} is the only key whose value not set to zero. How can map be used to change this value, but not any others given the same ('two', 'three') list?

Replies are listed 'Best First'.
Re: performing operation on elements not in list?
by gwadej (Chaplain) on Jan 09, 2009 at 21:17 UTC

    Leaving aside the whole map in void context discussion for a moment, let's take the question a little differently. How would you make a list of the keys that are not in the list ('two', 'three')?

    The answer to that is the answer to your question.

    G. Wade
Re: performing operation on elements not in list?
by ikegami (Patriarch) on Jan 09, 2009 at 21:41 UTC
    my %hash = (one => 1, two => 1, three => 1); my @keep = qw( two three ); my %keep = map { $_ => 1 } @keep; $hash{$_} = 0 for grep !$keep{$_}, keys %hash;
Re: performing operation on elements not in list?
by setebos (Beadle) on Jan 10, 2009 at 00:11 UTC
    Just decide which keys should be kept and which should not:
    my %hash = (one => 1, two => 1, three => 1); my %keep; @keep{ qw(two three) } = (); map { exists($keep{$_}) or $hash{$_} = 0 } keys(%hash);
Re: performing operation on elements not in list?
by johngg (Canon) on Jan 09, 2009 at 21:34 UTC

    Like this perhaps

    $ perl -le ' > %h = ( one => 1, two => 1, three => 1 ); > $inv = do{ local $" = q{|}; qr{^@{ [ qw{ two three } ] }$} }; > map $h{ $_ } = 0, grep ! /$inv/, keys %h; > print qq{$_ - $h{ $_ }} for keys %h;' three - 1 one - 0 two - 1 $

    Cheers,

    JohnGG

      Two errors.
      • You end up with qr/^two|three$/ which matches "twoo".
      • You don't convert the keys to regexp

      If the list of keys to keep is static, you want

      my $inv = qr/two|three/;

      If the list of keys to keep is dynamic, you want

      my $inv = do{ local $" = q{|}; qr{@{[ map quotemeta, @keep ]}} };

      or the much simpler

      my ($inv) = map qr/$_/, join '|', map quotemeta, @keep;

      In all cases, use /^$inv\z/ in the grep.

        Good catch regarding the anchors and alternation. The OP says "given the same ... list" so the keys not to change are invariable. So I should have said.

        $inv = do{ local $" = q{|}; qr{^(?:@{ [ qw{ two three } ] })$} };

        I'm not sure what you mean when you say I don't convert the keys to regexp.

        Cheers,

        JohnGG

Re: performing operation on elements not in list?
by zentara (Cardinal) on Jan 09, 2009 at 21:20 UTC
Re: performing operation on elements not in list?
by JavaFan (Canon) on Jan 10, 2009 at 10:53 UTC
    Untested:
    my @keep = qw [two three]; my %keep; @keep{@keep} = @hash{@keep}; map {$hash{$_} = 0} for keys %hash; @hash{@keep} = @keep{@keep};