不能使用数组作为Ruby Hash的默认值?

时间:2011-03-30 16:00:18

标签: ruby hash

我正在向哈希键添加项目。我期待得到这样的结构:

{ 
  'a' : [1],
  'b' : [2, 3, 4]
}

我使用了一个数组来初始化哈希。

irb> hash = Hash.new([])
 => {} 

然后开始使用它:

irb> hash['a'] << 1
 => [1] 
irb> hash['b'] << 2
 => [1, 2] 

但事实证明:

irb> hash
 => {}

4 个答案:

答案 0 :(得分:11)

请尝试以下方法:

hash = Hash.new{|h, k| h[k] = []}
hash['a'] << 1 # => [1]
hash['b'] << 2 # => [2]

您获得意外结果的原因是您将空数组指定为默认值,但使用了相同的数组;没有复制。正确的方法是使用新的空数组初始化值,就像我的代码一样。

答案 1 :(得分:4)

您使用constructor存储[]作为访问未知密钥时返回的默认值。由于Array#<<修改其接收器到位,这个最初为空的数组会增长。

更详细地解释:

执行hash['a'] << 1时会发生这种情况:

  1. hash查看是否存在名为'a'
  2. 的密钥
  3. 它发现没有,没有这样的钥匙。
  4. 查看是否存储了要返回的默认值。
  5. 由于您使用Hash.new([])构建了它,因此确实有[]这样的值,并返回该值。
  6. 现在[] << 1被评估,这意味着哈希现在存储[1]作为在请求先前未被发现的密钥时返回的值。
  7. 如果您想要存储键值对,请使用带有块的构造函数的第三种形式:

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

答案 2 :(得分:2)

hash['a'] << 1hash['b'] << 2不是创建键/值对的正确语法。您必须使用=

hash['a'] = []
hash['a'] << 1

hash['b'] = []
hash['b'] << 2

那应该给你哈希{'a' : [1], 'b' : [2]}

答案 3 :(得分:1)

这是完全您期望看到的行为。

您永远不会向Hash添加任何内容,因此Hash完全为空。当您查找某个键时,该键将永远不存在,因此它将返回默认值,您指定该值为Array

因此,您查找不存在的键'a',从而返回您指定为默认值的Array。然后,您在<<上致电Array,向其附加值(1)。

接下来,您查找也不存在的键'b',从而返回您指定为默认值的Array,现在包含元素1您之前补充说。然后,您在<<上致电Array,并将值2附加到其中。

你最终得到的Hash仍然是空的,因为你从来没有添加任何东西。 Hash的默认值现在是一个包含值12的数组。

您看到的输出是因为IRb始终打印已评估的最后一个表达式的结果。示例中的最后一个表达式是<<上的Array<<返回其接收器,然后是整个表达式的返回值,因此IRb打印出来。