12

次のルビーコードを試してみました。これは、単語の長さのハッシュをそれらの長さの単語に返すと思いました。代わりにそれは空です。

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

最初のバージョンが実際に意味するのは、デフォルト値が1つの配列のみであるということだと思います。2番目の例では、新しい配列がまだ存在しない場合は、明示的に作成します。

これは、さらに明確にするための良い読み物のように見えます。

于 2012-07-21T03:58:36.520 に答える