replace values in hash

Discussion in 'Ruby' started by Jason Lillywhite, Nov 5, 2008.

  1. how would I iterate over a hash, such as

    x = { 'a' => "hi", 'b' => nil, 'c' => "do"}

    and replace nil values with 'foo' then return the hash again?
     
    Jason Lillywhite, Nov 5, 2008
    #1
    1. Advertisements

  2. Jason Lillywhite

    Trans Guest

    x.each{ |k,v| x[k] =3D 'foo' unless v }

    However, it is not always sane to alter something while you are
    iterating over it. So,

    h =3D {}
    x.each{ |k,v| h[k] =3D v.nil? ? v : 'foo' }
    x.replace(h)

    Or use Facets Enumerable#mash (alias #graph)

    require 'facets/enumerable/mash'

    x =3D x.mash{ |k,v| [k, v.nil? ? v : 'foo'] }

    http://facets.rubyforge.org/doc/api/core/classes/Enumerable.html#M000429

    7.
     
    Trans, Nov 5, 2008
    #2
    1. Advertisements

  3. Thank you!

    However, I am getting undefined method 'mash' even though I do require
    'facets/enumerable/mash'

    am I missing something?
     
    Jason Lillywhite, Nov 5, 2008
    #3
  4. =20

    h.keys.each {|d| h[d] =3D "foo" if h[d] =3D=3D nil}
     
    Sarcar, Shourya C (GE Healthcare), Nov 5, 2008
    #4
  5. Jason Lillywhite

    Trans Guest

    Don't think so. It's working fine for me.

    What version of Ruby and Facets and what platform are you running?

    T.
     
    Trans, Nov 5, 2008
    #5
  6. Jason Lillywhite

    Brian Adkins Guest

    ~/temp$ cat -b temp.rb
    1 require 'pp'

    2 class Hash
    3 def replace_value old, new
    4 self.inject({}) do |result,pair|
    5 k, v = pair[0], pair[1]
    6 result[k] = (v == old) ? new : v
    7 result
    8 end
    9 end
    10 end

    11 x = { 'a' => "hi", 'b' => nil, 'c' => "do", :d => nil }
    12 pp x
    13 y = x.replace_value(nil, 'foo')
    14 pp y
    ~/temp$ ruby temp.rb
    {"a"=>"hi", "b"=>nil, :d=>nil, "c"=>"do"}
    {"a"=>"hi", "b"=>"foo", "c"=>"do", :d=>"foo"}
     
    Brian Adkins, Nov 5, 2008
    #6
  7. Jason Lillywhite

    Trans Guest

    For anyone who is interested, here's the definition (and some side
    notes about how it evolved).

    def mash(&yld)
    if yld
    inject({}) do |h, *kv| # Used to be inject({}) do |h,kv|
    r =3D *yld[*kv] # The *-op works different from to_a on
    single element hash!!!
    nk, nv =3D *r # Used to be nk, nv =3D
    *yld[*kv].to_a.flatten
    h[nk] =3D nv
    h
    end
    else
    Enumerator.new(self,:mash) # Used to be Hash[*self.to_a]
    end
    end

    T.
     
    Trans, Nov 5, 2008
    #7
  8. [Note: parts of this message were removed to make it a legal post.]

    Not bad. Let's tighten it up a little:

    class Hash
    def replace_value(old, new)
    self.inject({}) do |result, (key, existing_value)|
    result[key] = (value == old) ? new : existing_value
    result
    end
    end
    end

    This isn't bad, but you wouldn't want to do this for large Hashes since you
    end up copying the original.

    James

     
    James Herdman, Nov 10, 2008
    #8
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.