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

I want to operate on some values in a hash

by misterperl (Pilgrim)
on Jan 04, 2018 at 16:08 UTC ( [id://1206694]=perlquestion: print w/replies, xml ) Need Help??

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

I have a hash. I want to select out some of the values, and do something just to those. My approach now is
1. select keys with some regex like my @k = grep /something/,keys %h 2. loop over those keys like for ( @k ) { $h{$_} = some change } or { $h{$_} =~ s/stuff/other stuff/ }
what I'd prefer, as I'm averse to for () in general, is more like map s/something/something else/, over the values, and there is the problem. Is there some sensible construct to handle that sans looping? I'm considering something like map s/x/y/, @h{@k} ? Thanks, and Happy New Year to all.

Replies are listed 'Best First'.
Re: I want to operate on some values in a hash
by Eily (Monsignor) on Jan 04, 2018 at 16:15 UTC

    I'm averse to for ()
    Why? The intended meaning of map is to create a new list from an old one. So modifying a set of values with map (rather than create a new set) is considered bad practice. You might do @h{@k} = map { stuff($_) } @h{@k} if you really want to avoid a for loop, or s/stuff/other/ for @h{@k}; if it's having multiple lines that bothers you.

    Edit: when I say that modifying a set of values with map is considered bad practice, I'm talking about the inplace modification of elements, as in map { $_ += 2 } @numbers;, (or the dreaded "map in void context"). @h{@k} = map { stuff($_) } @h{@k} isn't as bad, as it actually builds a temporary new list, before overwriting the values in the hash. It's just neither the most straightforward way, nor the usual way. But as long as there's no inplace editing, that's fine IMHO.

      I agree with Eily that using map for in-place modification is bad practice. I think you could just use filter & map to produce newly generated hash.
      my %modified_hash = map { $_ => f($hash{$_}) grep { condition_on_key($_) } keys(%hash);
      Edit: s/list/hash/
      Eily: " modifying a set of values with map (rather than create a new set) is considered bad practice" I'd actually never read that, can you elaborate? I often do that with great success. But if there are side-effects or dangers I'm not aware of I'd like to know that.. Thanks

        I suppose you wrote that before I edited my message?

        Honestly I can't remember seeing the map in void context for a while, except when I mention that people keep bringing up the subject myself (but I did see it often in my earlier readings on perlmonks), make of that what you will.

        One reason for the discussion is that map is supposed to build a new list, and not using that output is a waste of resources. But even if map wasn't smart about its context, it's perl, you're supposed to ignore performance issues most of the time and focus on getting things done. The other issue is when you use the aliasing mechanism, ie the fact that modifying $_ will modify the input. Since ; map { $_ += 2 } @numbers; and ; $_ += 2 for @numbers; do exactly the same thing, it's clearer if you use the version that's not supposed to create a separate output. Best reason to use the second version is that you won't get told that there's a better way to do it when you post it on perlmonks :D

        NB: even without using the aliasing mechanism: ; map { $h{$_}++} @keys; may be better written as ; $h{$_}++ for @keys;, because map does something from the input, while for does something with the input. Nitpicking at its finest :)

        It's strictly verboten since the birth of the cool AKA hour zero or so. May be one of our founders imposed this but no one remembers who it really was. But remember: Things that are verboten - like perl -E 'map {++$_; say;} 0..9' - give the real kick ;-) For a more serious debate please see map vs for\foreach..

        Best regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

        perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: I want to operate on some values in a hash
by choroba (Cardinal) on Jan 04, 2018 at 18:02 UTC
    You were very close:
    s/stuff/other stuff/ for @h{ grep /something/, keys %h }
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: I want to operate on some values in a hash
by AnomalousMonk (Archbishop) on Jan 04, 2018 at 18:30 UTC
    I'm considering something like ...

    So what happened when you tried it?

    c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le "my %h = qw(foo oofzle bar rabzle quux xuuqzle fee eefzle); dd \%h; ;; my @k = grep m{ foo | bar }xms, keys %h; ;; map s/zle/DING/, @h{ @k }; dd \%h; " { bar => "rabzle", fee => "eefzle", foo => "oofzle", quux => "xuuqzle" + } { bar => "rabDING", fee => "eefzle", foo => "oofDING", quux => "xuuqzl +e" }
    Although I have to say I don't understand your general for-aversion — and map contains an implicit loop!

    Update: Small change to example code to make it closer to structure of OPed pseudo-code.


    Give a man a fish:  <%-{-{-{-<

Re: I want to operate on some values in a hash
by thanos1983 (Parson) on Jan 04, 2018 at 16:19 UTC

    Hello misterperl,

    Why not simply rename the key on the flow?

    Sample of code:

    Update: For multiple keys you can use hash slice:

    Update2: Update the keys with for loop:

    Update3: Also with map (I think this is slower):

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-03-29 13:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found