在Ruby中更改散列中的每个值
我想改变散列中的每个值,以便在值的前后添加'%'
{ :a=>'a' , :b=>'b' }
必须改成
{ :a=>'%a%' , :b=>'%b%' }
什么是最好的方法来做到这一点?
如果你想让实际的string本身在适当的位置进行变异(可能并希望影响对相同string对象的其他引用):
# Two ways to achieve the same result (any Ruby version) my_hash.each{ |_,str| str.gsub! /^|$/, '%' } my_hash.each{ |_,str| str.replace "%#{str}%" }
如果你想要改变散列,但你不想影响string(你希望它得到新的string):
# Two ways to achieve the same result (any Ruby version) my_hash.each{ |key,str| my_hash[key] = "%#{str}%" } my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }
如果你想要一个新的哈希:
# Ruby 1.8.6+ new_hash = Hash[*my_hash.map{|k,str| [k,"%#{str}%"] }.flatten] # Ruby 1.8.7+ new_hash = Hash[my_hash.map{|k,str| [k,"%#{str}%"] } ]
在Ruby 2.1和更高版本中,你可以做
{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h
修改哈希值的最佳方法是
hash.update(hash){ |_,v| "%#{v}%" }
代码less,意图明确。 也更快,因为没有新的对象分配超出必须改变的值。
更可读一个, map
其map
到一个单元哈希数组,并reduce
merge
the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)
Ruby 2.4引入了方法Hash#transform_values!
,你可以使用。
{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" } # => {:a=>"%a%", :b=>"%b%"}
一种不会对原件带来副作用的方法:
h = {:a => 'a', :b => 'b'} h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]
Hash#map也可能是一个有趣的读取,因为它解释了为什么Hash.map
不返回Hash(这就是为什么[key,value]
对的结果数组被转换为新的Hash),并提供了替代方法相同的一般模式。
快乐的编码。
[免责声明:我不确定在Ruby 2.x中Hash.map
语义是否改变]
这个任务有一个新的“Rails方式”方法:) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values
my_hash.each do |key, value| my_hash[key] = "%#{value}%" end
Hash.merge! 是最干净的解决scheme
o = { a: 'a', b: 'b' } o.merge!(o) { |key, value| "%#{ value }%" } puts o.inspect > { :a => "%a%", :b => "%b%" }
在用RSpectesting之后,像这样:
describe Hash do describe :map_values do it 'should map the values' do expect({:a => 2, :b => 3}.map_values { |x| x ** 2 }).to eq({:a => 4, :b => 9}) end end end
你可以像下面这样实现Hash#map_values:
class Hash def map_values Hash[map { |k, v| [k, yield(v)] }] end end
该function可以像这样使用:
{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" } # {:a=>"%a%", :b=>"%b%"}