如何更改哈希值?

我想用 value.some_method替换散列中的每个 value

例如,对于给定的简单散列:

{"a" => "b", "c" => "d"}`

每个值都应该是 .upcased,这样看起来就像:

{"a" => "B", "c" => "D"}

我尝试了 #collect#map,但是总是返回数组。有没有一种优雅的方法可以做到这一点?

更新

该死,我忘了: 散列在一个不应该改变的实例变量里。我需要一个具有更改值的新散列,但不希望显式定义该变量,然后在填充该变量的散列上循环。比如:

new_hash = hash.magic{ ... }
143151 次浏览
my_hash.each { |k, v| my_hash[k] = v.upcase }

或者,如果您希望以非破坏性方式执行,并返回一个新的 hash 而不是修改 my_hash:

a_new_hash = my_hash.inject({}) { |h, (k, v)| h[k] = v.upcase; h }

最后一个版本还有一个额外的好处,那就是您也可以转换键。

试试这个功能:

h = {"a" => "b", "c" => "d"}
h.each{|i,j| j.upcase!} # now contains {"a" => "B", "c" => "D"}.

我会这样做:

New _ Hash = Hash [ * first _ Hash. Collection { | key,value | [ key,value + 1]} . flatten ]

这也为您提供了通过任何表达式转换键或值的工具(当然,这是非破坏性的)。

您可能需要更进一步,在嵌套散列上执行此操作。当然,这在 Rails 项目中发生的次数相当多。

下面是一些确保 params 散列为 UTF-8的代码:

  def convert_hash hash
hash.inject({}) do |h,(k,v)|
if v.kind_of? String
h[k] = to_utf8(v)
else
h[k] = convert_hash(v)
end
h
end
end


# Iconv UTF-8 helper
# Converts strings into valid UTF-8
#
# @param [String] untrusted_string the string to convert to UTF-8
# @return [String] your string in UTF-8
def to_utf8 untrusted_string=""
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
ic.iconv(untrusted_string + ' ')[0..-2]
end

您可以收集这些值,并再次将其从 Array 转换为 Hash。

像这样:

config = Hash[ config.collect {|k,v| [k, v.upcase] } ]

这样就行了:

my_hash.each_with_object({}) { |(key, value), hash| hash[key] = value.upcase }

inject相反,其优点是不需要在块内再次返回哈希。

Ruby 有 tap方法(1.8.71.9.32.1.0) ,对于类似这样的东西非常有用。

original_hash = { :a => 'a', :b => 'b' }
original_hash.clone.tap{ |h| h.each{ |k,v| h[k] = v.upcase } }
# => {:a=>"A", :b=>"B"}
original_hash # => {:a=>"a", :b=>"b"}

特定于 Rails 的

如果某人只需要对每个值调用 to_s方法而不使用 Rails4.2(其中包括 transform_values方法 链接) ,您可以执行以下操作:

original_hash = { :a => 'a', :b => BigDecimal('23.4') }
#=> {:a=>"a", :b=>#<BigDecimal:5c03a00,'0.234E2',18(18)>}
JSON(original_hash.to_json)
#=> {"a"=>"a", "b"=>"23.4"}

注意: 需要使用“ json”库。

注意2: 这也将把键转换成字符串

ActiveSupport v4.2.0中有一个方法可以解决这个问题,它叫做 transform_values,基本上就是为每个键-值对执行一个代码块。

因为他们使用的是 each,我认为没有比循环更好的方法了。

hash = {sample: 'gach'}


result = {}
hash.each do |key, value|
result[key] = do_stuff(value)
end

更新:

从 Ruby 2.4.0开始,您就可以在本地使用 #transform_values#transform_values!

如果知道这些值是字符串,可以在循环中调用它们的 更换方法: 这样就可以更改值。

虽然这仅限于值是字符串的情况,因此不能完全回答这个问题,但我认为它对某些人是有用的。

new_hash = old_hash.merge(old_hash) do |_key, value, _value|
value.upcase
end


# old_hash = {"a" => "b", "c" => "d"}
# new_hash = {"a" => "B", "c" => "D"}

因为 ruby 2.4.0可以使用原生的 Hash#transform_values方法:

hash = {"a" => "b", "c" => "d"}
new_hash = hash.transform_values(&:upcase)
# => {"a" => "B", "c" => "D"}

也有破坏性的 Hash#transform_values!版本。