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

它确实有效。

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

4

3 回答 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

现在它按预期工作。

于 2012-07-21T04:07:17.780 回答
12

综上所述,检查Enumerable#group_by

["abc", "def", "four", "five"].group_by(&:length)
#=> {3=>["abc", "def"], 4=>["four", "five"]}
于 2012-07-21T07:26:00.203 回答
2

我认为第一个版本的真正含义是默认值只有一个数组。如果新数组尚不存在,则第二个示例显式创建一个新数组。

这看起来像一个很好的阅读来进一步澄清

于 2012-07-21T03:58:36.520 回答