使用each_with_object初始化的Ruby Hash表现得非常奇怪

时间:2017-06-15 11:46:47

标签: ruby hash

初始化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"]}

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

3 个答案:

答案 0 :(得分:3)

是的,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] = [] }

答案 1 :(得分:0)

所有密钥引用相同的数组。

解释问题的简化版本:

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

答案 2 :(得分:-1)

为什么要将它们放在一个数组中,然后将它们放入哈希?如果我理解你的问题,你可能想要这样做:

hash = {'1'=>"",'2'=>"",'3'=>""}
hash['1'] = 'a'
hash['2'] = 'b'
hash['3'] = 'Hello' 

如果对象的类不满足您的要求,您可以在整数或任何您想要的之后转换它们! 希望能帮助到你!