在Ruby中更改散列中的每个值

the*_*ick 158 ruby hash

我想更改散列中的每个值,以便在值之前和之后添加'%'

{ :a=>'a' , :b=>'b' }
Run Code Online (Sandbox Code Playgroud)

必须改为

{ :a=>'%a%' , :b=>'%b%' }
Run Code Online (Sandbox Code Playgroud)

最好的方法是什么?

sho*_*one 254

在Ruby 2.1及更高版本中,您可以做到

{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h
Run Code Online (Sandbox Code Playgroud)

  • 但是,这非常慢,而且RAM非常饥饿.迭代输入Hash以生成一组中间嵌套数组,然后将其转换为新的Hash.忽略RAM峰值使用情况,运行时间要差得多 - 在相同的迭代次数中,基准测试与另一个答案中的现场修改解决方案相比,显示2.5s与1.5s.由于Ruby是一种相对较慢的语言,避免慢速语言的慢点使得很有意义:-) (7认同)
  • 谢谢,实际上我正在寻找.不知道为什么你没有那么多投资. (5认同)
  • 如果您使用 Ruby 2.4+,如 sschmeck (/sf/answers/2905575011/) 所指出的那样,使用 `#transform_values!` 会更容易。 (5认同)
  • 难题是:嗯,我们已经放弃了我们决定使用红宝石的表现,那么"另外一点点"会有什么不同呢?这是一个滑坡,不是吗?为了记录,从可读性的角度来看,我确实更喜欢这个解决方案. (4认同)
  • @AndrewHodgkinson虽然总体上我同意并且不主张不关注运行时性能,但是是否不跟踪所有这些性能陷阱却开始变得痛苦并与“开发人员生产力优先”的红宝石哲学背道而驰?我想这对您来说不是一个评论,而更多地是关于最终使用Ruby带来的悖论的一般评论。 (2认同)

Phr*_*ogz 168

如果您希望实际的字符串本身在适当的位置发生变异(可能并且希望影响对相同字符串对象的其他引用):

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

如果您希望哈希值就地更改,但您不想影响字符串(您希望它获取新字符串):

# 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 }
Run Code Online (Sandbox Code Playgroud)

如果你想要一个新的哈希:

# 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}%"] } ]
Run Code Online (Sandbox Code Playgroud)

  • 实际上,Hash.[key_value_pairs]是在1.8.7中引入的,所以只有Ruby 1.8.6不需要splat和flatten. (2认同)
  • @Aupajo`Hash#each`产生块的键和值.在这种情况下,我不关心密钥,所以我没有说出任何有用的东西.变量名可以以下划线开头,实际上可能是_just_下划线.这样做没有性能上的好处,它只是一个微妙的自我记录说明,我没有对第一个块值做任何事情. (2认同)
  • 或者,您可以使用each_value 方法,这比使用下划线表示未使用的键值更容易理解。 (2认同)

ssc*_*eck 98

Ruby 2.4引入了Hash#transform_values!您可以使用的方法.

{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"} 
Run Code Online (Sandbox Code Playgroud)

  • 当然还有 [`Hash#transform_values`](https://docs.ruby-lang.org/en/2.4.0/Hash.html#method-i-transform_values)(没有爆炸),它没有t 修改接收器。否则是一个很好的答案,谢谢! (8认同)
  • 这真的会*减少*我对 [`reduce`](https://docs.ruby-lang.org/en/2.4.0/Enumerable.html#method-i-reduce) 的使用:-p (3认同)

Sim*_*Sim 80

修改哈希值的最佳方法是

hash.update(hash){ |_,v| "%#{v}%" }
Run Code Online (Sandbox Code Playgroud)

更少的代码和明确的意图.也更快,因为除了必须更改的值之外没有分配新对象.

  • 与我的答案相同,但有另一个同义词,我同意`update`比'merge!'更好地表达了意图.我认为这是最好的答案. (3认同)

edg*_*ner 28

更可读的一个,map它是一个单元素哈希数组和reduce那个merge

the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)
Run Code Online (Sandbox Code Playgroud)

  • 更清楚使用`哈希[the_hash.map {|键,值| [key,"%#{value}%"]}]` (2认同)

wot*_*oto 17

这项任务有一种新的'Rails方法':) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values

  • Ruby 2.4.0+还包含[`Hash#transform_values`](https://ruby-doc.org/core-2.4.0/Hash.html#method-i-transform_values).这应该是从现在开始的方式. (5认同)

小智 16

一种不会对原件产生副作用的方法:

h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]
Run Code Online (Sandbox Code Playgroud)

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

快乐的编码.

[免责声明:我不确定Hash.mapRuby 2.x中的语义是否会发生变化]

  • Matz甚至知道Ruby 2.x中的`Hash.map`语义是否有变化? (7认同)

And*_*all 15

my_hash.each do |key, value|
  my_hash[key] = "%#{value}%"
end
Run Code Online (Sandbox Code Playgroud)


小智 7

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

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

puts o.inspect
> { :a => "%a%", :b => "%b%" }
Run Code Online (Sandbox Code Playgroud)


wed*_*oft 5

用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
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式实现Hash#map_values:

class Hash
  def map_values
    Hash[map { |k, v| [k, yield(v)] }]
  end
end
Run Code Online (Sandbox Code Playgroud)

然后可以使用这个函数:

{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" }
# {:a=>"%a%", :b=>"%b%"}
Run Code Online (Sandbox Code Playgroud)