Ruby如何将值为数组的数据添加到哈希表中?

12

我尝试了下面这段Ruby代码,以为会返回一个将单词长度映射到该长度的单词列表的哈希表,但实际上是空的。

map = Hash.new(Array.new)    
strings = ["abc","def","four","five"]
strings.each do |word|
  map[word.length] << word  
end   

然而,如果我将其修改为

map = Hash.new
strings = ["abc","def","four","five"]
strings.each do |word|
  map[word.length] ||= []
  map[word.length] << word  
end

它确实起作用。

第一个版本只是创建一个默认值为空数组的哈希表吗?在这种情况下,我不明白为什么两个块会给出不同的值。


这很奇怪。对于第一个例子,如果你执行map = Hash.new {|h,k| h[k] = [] },它就能工作。 - Benjamin Tan Wei Hao
3个回答

30
问题在于你并没有实际给哈希键分配任何内容,你只是使用了<<运算符来修改默认值的现有内容。由于你没有给哈希键赋值,所以它不会被添加。事实上,你会注意到默认值是被修改的。
h = Hash.new []
p h[0]           # []
h[0] << "Hello"
p h              # {}
p h[0]           # ["Hello"]
p h[1]           # ["Hello"]

这是因为同一个Array对象被保留为默认值。您可以使用+运算符来修复它,尽管这可能不太高效:

map = Hash.new []
strings = ["abc", "def", "four", "five"]

strings.each do |word|
    map[word.length] += [word]
end

现在它按预期工作。


帮了我很多,谢谢!但是直到我将 += 后面的 word 改为数组形式,如 [word],它才对我起作用。 - Subtletree

12

总之,可以查看Enumerable#group_by

["abc", "def", "four", "five"].group_by(&:length)
#=> {3=>["abc", "def"], 4=>["four", "five"]}

谢谢。我还在学习 Ruby,所以学习惯用语很有帮助。 - Jeff Storey

2
我认为第一个版本的真正意思是默认值只有一个数组。如果尚未存在数组,则第二个示例会显式创建一个新数组。
这看起来像是进一步澄清的好文章(链接)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接