在 Ruby 中更改 hash 中的值

我想改变哈希中的每个值,以便在值的前面和后面添加'%'

{ :a=>'a' , :b=>'b' }

必须改为

{ :a=>'%a%' , :b=>'%b%' }

最好的方法是什么?

166414 次浏览

有一种方法不会给原药带来副作用:

h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]

散列#地图也可能是一个有趣的阅读,因为它解释了为什么Hash.map不返回哈希(这就是为什么[key,value]对的结果数组被转换为一个新的哈希),并提供了相同一般模式的替代方法。

快乐的编码。

[免责声明:我不确定Ruby 2.x中的Hash.map语义是否有变化]

my_hash.each do |key, value|
my_hash[key] = "%#{value}%"
end

如果你想让实际的字符串本身发生变化(可能会影响到对相同字符串对象的其他引用):

# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |_,str| str.gsub! /^|$/, '%' }
my_hash.each{ |_,str| str.replace "%#{str}%" }

如果你想要改变哈希值,但你不想影响字符串(你想让它得到新的字符串):

# 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}%"] } ]

更容易读的是,map是一个单元素哈希数组,而reduce是带有merge的数组

the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)

Hash.merge !这是最干净的解决方案吗

o = { a: 'a', b: 'b' }
o.merge!(o) { |key, value| "%#{ value }%" }


puts o.inspect
> { :a => "%a%", :b => "%b%" }

在Ruby 2.1及更高版本中你可以这样做

{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h

修改哈希值的最佳方法是

hash.update(hash){ |_,v| "%#{v}%" }

更少的代码和清晰的意图。而且更快,因为除了必须更改的值之外,没有分配新的对象。

这个任务有一个新的'Rails way'方法:) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values < / p >

在用RSpec测试之后,就像这样:

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

你可以像下面这样实现哈希#map_values:

class Hash
def map_values
Hash[map { |k, v| [k, yield(v)] }]
end
end

函数可以这样使用:

{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" }
# {:a=>"%a%", :b=>"%b%"}

Ruby 2.4引入了Hash#transform_values!方法,你可以使用它。

{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"}

如果你好奇哪个原地变量是最快的,下面是:

Calculating -------------------------------------
inplace transform_values! 1.265k (± 0.7%) i/s -      6.426k in   5.080305s
inplace update      1.300k (± 2.7%) i/s -      6.579k in   5.065925s
inplace map reduce    281.367  (± 1.1%) i/s -      1.431k in   5.086477s
inplace merge!      1.305k (± 0.4%) i/s -      6.630k in   5.080751s
inplace each      1.073k (± 0.7%) i/s -      5.457k in   5.084044s
inplace inject    697.178  (± 0.9%) i/s -      3.519k in   5.047857s