Ruby Hash初始化时each_with_object行为怪异



初始化Ruby Hash,就像:

keys = [0, 1, 2]
hash = Hash[keys.each_with_object([]).to_a]

尝试将值插入键时行为异常。

hash[0].push('a')
# will result into following hash:
=> {0=>["a"], 1=>["a"], 2=>["a"]}

我只是想插入一个键,但它正在更新所有键的值。

是的,这个each_with_object本身就非常奇怪。这不是应该如何使用它。问题正是因为你误用了它。

keys.each_with_object([]).to_a
# => [[0, []], [1, []], [2, []]]

你看,即使看起来这些数组是分开的,但在所有三种情况下它实际上是同一个数组。这就是为什么如果你把一个元素推入一个元素,它就会出现在所有其他元素中。

这里有一个更好的方法:

h = keys.each_with_object({}) {|key, h| h[key] = []}
# => {0=>[], 1=>[], 2=>[]}

或者,说

h = keys.zip(Array.new(keys.size) { [] }).to_h

或者其他一些方式。

如果您不关心哈希具有这组确切的键,而只是希望所有键都具有空数组作为默认值,那也是可能的。

 h = Hash.new { |hash, key| hash[key] = [] }

所有键都引用同一个数组。

解释问题的简化版本:

a = []
b = a
a.push('something')
puts a #=> ['something']
puts b #=> ['something']

即使你有两个变量(ab(,也只有一个数组对象。因此,对变量 a 引用的数组的任何更改也会更改变量 b 引用的数组。因为它是同一个对象。

您要实现的目标的长版本将是:

keys = [1, 2, 3]
hash = {}
keys.each do |key|
  hash[key] = []
end

还有一个更短的版本:

[1, 2 ,3].each_with_object({}) do |key, accu|
  accu[key] = []
end

相关内容

最新更新