in reply to Re: setting values in anonymous hash
in thread setting values in anonymous hash

quidity suggests:
> %new_hash = map {defined($_) ? $_ : ''} %{$ref2};
In recent versions of Perl, you can also use a simpler version that modifies the hash in place:
map { $_ = '' unless defined } %$ref2;
This is comparable in simplicity to the original code that involved an array instead of a hash.

Replies are listed 'Best First'.
Re: Re: setting values in anonymous hash
by merlyn (Sage) on Nov 28, 2000 at 21:53 UTC
    map { $_ = '' unless defined } %$ref2;
    To eliminate the void map, and not attack the keys (which don't need attacking), I'd go with:
    defined or $_ = "" for @$ref2{keys %$ref2};
    or for 5.6 and later:
    defined or $_ = "" for values %$ref2;

    -- Randal L. Schwartz, Perl hacker

      Says merlyn:
      > To eliminate the void map ...
      I knew you were going to show up and say this, so please allow me to register my respectful disagreement on the subject of void map. I never understood why you thought it was such a big deal.

        The thing is, for people with a clear understanding of what the parser is doing, using the side-effect of a command isn't that big of a deal. OTOH for people who are still picking up the language, not knowing the consequences of ignoring the return can realy freak you out.

        I did something like the following once, thanks to cut-n-pasting someone else's solution. There was a lot of intervening code in the original case but it came down to this:

        #!/usr/bin/perl -w my @list=(4,3,2,5,1); # db access here for more data. # the numbers that follow were real ugly in the original # code, like $sql->return->[0][2] and suchlike... push @list, 45, 6, 24, 43, 9, # Comma not semicolon map {$_ *= 2} @list; print "@list\n"; # prints: # 8 6 4 10 2 45 6 24 43 9 4 3 2 5 1

        That was how I learned about abusing void context. =) Took me quite a while to spot that little goofup. If I'd written it the "right" way with a foreach: foreach (@list) { $_ *= 2; } I would have at least got a syntax error NEAR the error.

        Of course, merlyn's fancy postfix for trick: $_++ for @l; in place of the map nets you an infinite loop in this case. =)

        In any case, it seems wrong to ask perl to build up a return list from the map just to ignore it. If your only job is holding a nut while someone else tightens the bolt, you use a box-wrench, not a ratchet. Using a ratchet isn't "wrong" but it is still the wrong tool for the job. =)

        Of course, now that I've gotten cocky, I abuse side effects ever so often myself. I just try not to do it to at work where some poor schmuck will have to puzzle out what I did.

        --
        $you = new YOU;
        honk() if $you->love(perl)

      Here's my stupid question for today. I suppose if I really wanted to know, I could load up 5.005. Why doesn't: defined or $_ = "" for values %$ref2; Work for versions < 5.6?
        Starting in 5.6.0, the elements in the list returned by values() are the actual values of the hash. Before that, the elements returned by values() were copies of the values from the hash. This is mentioned in 5.6.0's perldelta documentation.
Re: Re: setting values in anonymous hash
by snax (Hermit) on Nov 28, 2000 at 22:03 UTC
    OK, I'm confused. map wants a list, right? So here you're treating the hash as a list, and setting the undefined values to '' as you find them?

    I think that this method would make more sense to me if it went something like

    map { $_ = '' unless defined } values %$ref2;
    I guess I'm just wondering why referring to hashes in a list context is a good idea.

    Update: merlyn rightly points out this is a void usage of map. Perusing the docs for map led me to some insight. We want to test for values that are undefined and change them -- sounds like a job for grep:

    for (grep {not defined} values %$ref2) {$_ = q()};
    fits the bill -- it actually acts on the returned values from grep, so no more void contexts, and actually reads like the task desired.

      Says snax:
      > map wants a list, right?
      Right.
      > So here you're treating the hash as a list, and
      > setting the undefined values to '' as you find them?
      Right. See, you weren't as confused as you thought.
      > I guess I'm just wondering why referring to hashes
      > in a list context is a good idea.
      Uh uh. Innocent until proven guilty. It solves the problem, so the burden of proof is on you to show why it isn't a good idea.

      We use hashes as lists all the time:

      sub stuff { my %hash ; ... return %hash; } %stuff = stuff();
      It isn't a big deal.
        I had no intention of calling you guilty -- I was honestly wondering about the whole hash-in-list-context thing. I have used this "feature" myself before but long ago, before I started using -w and strict. Since then I've always felt oddly guilty using hashes like that -- that I was obfuscating, which isn't usually a good idea when you are using code for "real" purposes.