Replace values in hash


#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?


#2

On Nov 5, 1:53 am, Jason L. removed_email_address@domain.invalid
wrote:

how would I iterate over a hash, such as

x = { ‘a’ => “hi”, ‘b’ => nil, ‘c’ => “do”}

x.each{ |k,v| x[k] = ‘foo’ unless v }

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

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

Or use Facets Enumerable#mash (alias #graph)

require ‘facets/enumerable/mash’

x = x.mash{ |k,v| [k, v.nil? ? v : ‘foo’] }

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


#3

Thank you!

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

am I missing something?


#4

I guess since Enumerable is a Module, I need to do

include Enumerable… Thanks for the solution!


#5

-----Original Message-----
From: removed_email_address@domain.invalid [mailto:removed_email_address@domain.invalid]
Sent: Wednesday, November 05, 2008 12:24 PM
To: ruby-talk ML
Subject: replace values in hash

how would I iterate over a hash, such as

x = { ‘a’ => “hi”, ‘b’ => nil, ‘c’ => “do”}

h.keys.each {|d| h[d] = “foo” if h[d] == nil}


#6

On Nov 5, 2:54 am, Jason L. removed_email_address@domain.invalid
wrote:

Thank you!

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

am I missing something?

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

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

T.


#7

On Nov 5, 10:31 am, Trans removed_email_address@domain.invalid wrote:

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

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

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 = *yld[*kv] # The *-op works different from to_a on
single element hash!!!
nk, nv = *r # Used to be nk, nv =
*yld[*kv].to_a.flatten
h[nk] = nv
h
end
else
Enumerator.new(self,:mash) # Used to be Hash[*self.to_a]
end
end

T.


#8

Jason L. removed_email_address@domain.invalid writes:

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?

~/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”}


#9

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