有时我想映射一个集合。 如果它是一个阵列很容易:
foo = [1,2,3]
foo.map {|v| v + 1}
#=> [2, 3, 4]
但哈希的工作原理并不相同:
bar = {a: 1, b: 2, c: 3}
bar.map{|k,v| v+1}
#=> [2, 3, 4]
我真正喜欢的是:
bar = {a: 1, b: 2, c: 3}
bar.baz{|k,v| v+1}
#=> {:a=>2, :b=>3, :c=>4}
其中Hash#baz
是某种方法。是否有一种简单的方法来获得类似地图的"哈希的体验?
答案 0 :(得分:10)
在Ruby 2.4中,您可以使用内置的Hash#transform_values
:
bar = {a: 1, b: 2, c: 3}
# => {:a=>1, :b=>2, :c=>3}
bar.transform_values {|v| v+1 }
# => {:a=>2, :b=>3, :c=>4}
答案 1 :(得分:4)
从ruby-forum,您可以使用Hash#merge将哈希与自身合并:
bar = {a: 1, b: 2, c: 3}
#=> {:a=>1, :b=>2, :c=>3}
bar.merge(bar){|k,v| v+1}
#=> {:a=>2, :b=>3, :c=>4}
答案 2 :(得分:3)
关于Ruby的一个好处是,如果你不喜欢Ruby核心中的内容,你总是可以去扩展它来填补缺失的部分:
class Hash
def map_values
map do |k,v|
[ k, yield(k, v) ]
end.to_h
end
end
它为您提供了您想要的东西:
bar = {a: 1, b: 2, c: 3}
# => {:a=>1, :b=>2, :c=>3}
bar.map_values{ |k,v| v+1 }
# => {:a=>2, :b=>3, :c=>4}
我很惊讶这并没有被引入核心Ruby,但它可能在未来。
更新:正如Eric指出的那样,transform_values
现在在Ruby 2.4.0中。如果您使用的是Rails 4.2或更高版本,那么这也在ActiveSupport中。
bar = {a: 1, b: 2, c: 3}
# => {:a=>1, :b=>2, :c=>3}
bar.transform_values{ |v| v+1 }
# => {:a=>2, :b=>3, :c=>4}
答案 3 :(得分:2)
只是指出解决这一需求的明显且最常见的解决方案:
bar = {a: 1, b: 2, c: 3}
# => {:a=>1, :b=>2, :c=>3}
bar.map { |k, v| [k, v + 1] }.to_h
# => {:a=>2, :b=>3, :c=>4}
答案 4 :(得分:1)
bar = {a: 1, b: 2, c: 3}
bar.merge(bar) { |*,v| v+1 }
#=> {:a=>2, :b=>3, :c=>4}
这使用Hash.merge的形式,它使用一个块来返回合并的两个哈希中存在的键的值,这里是所有键。
另一种方式:
bar.keys.each { |k| bar[k] += 1 }
bar
#=> {:a=>2, :b=>3, :c=>4}
可以使用Object#tap在一行中写入:
bar.tap { |h| h.keys.each { |k| h[k] += 1 } }
#=> {:a=>2, :b=>3, :c=>4}