41

デフォルトのメソッドがハッシュに対して何をするかを理解したと思いました...

キーが存在しない場合は、デフォルト値を指定します。

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = 4
=> 4
irb(main):003:0> a[8]
=> 4
irb(main):004:0> a[9] += 1
=> 5
irb(main):005:0> a
=> {9=>5}

すべて良い。

しかし、デフォルトを空のリストまたは空のハッシュに設定すると、その動作がまったくわかりません...。

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9]                          # great!
irb(main):004:0> a
=> {}                           # ?! would have expected {8=>[9]}
irb(main):005:0> a[8]
=> [9]                          # awesome!
irb(main):006:0> a[9]
=> [9]                          # unawesome! shouldn't this be [] ??

||=演算子を使用した場合と同じ動作を期待/期待していました...

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a[8] ||= []
=> []
irb(main):003:0> a[8] << 9
=> [9]
irb(main):004:0> a
=> {8=>[9]}
irb(main):005:0> a[9]
=> nil

誰かが何が起こっているのか説明できますか?

4

7 に答える 7

54

これは非常に便利なイディオムです:

(myhash[key] ||= []) << value

ネストすることもできます:

((myhash[key1] ||= {})[key2] ||= []) << value

もう1つの方法は次のとおりです。

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

しかし、これには、キーについて尋ねるとキーが作成されるという重大な副作用があり、これは has_key? をレンダリングします。かなり役に立たないので、この方法は避けています。

于 2008-10-10T18:02:35.210 に答える
51

Hash.default存在しないキーを照会したときに返されるデフォルト値を設定するために使用されます。コレクションのエントリは、クエリされたという理由だけで作成されません。

また、設定defaultする値はオブジェクトのインスタンス(この場合は配列)であるため、これが返されたときに操作できます。

a = {}
a.default = []     # set default to a new empty Array
a[8] << 9          # a[8] doesn't exist, so the Array instance is returned, and 9 appended to it
a.default          # => [9]
a[9]               # a[9] doesn't exist, so default is returned
于 2008-10-10T10:48:54.817 に答える
34

これがあなたが探している動作だと思います。これにより、ハッシュ内の新しいキーが配列に自動的に初期化されます。

irb(main):001:0> h = Hash.new{|h, k| h[k] = []}
=> {}
irb(main):002:0> h[1] << "ABC"
=> ["ABC"]
irb(main):003:0> h[3]
=> []
irb(main):004:0> h
=> {1=>["ABC"], 3=>[]}
于 2008-10-11T16:39:26.407 に答える
9

グレン・マクドナルド さんのコメント:

「もう1つの方法は、次のことです。

myhash = Hash.new {|ハッシュ、キー| ハッシュ[キー] = []}

しかし、これには、キーについて尋ねるとキーが作成されるという重大な副作用があり、これは has_key? をレンダリングします。かなり役に立たないので、この方法は避けています。」

それは実際には真実ではないようです。

irb(main):004:0> a = Hash.new {|hash,key| hash[key] = []}
=> {}
irb(main):005:0> a.has_key?(:key)
=> false
irb(main):006:0> a[:key]
=> []
irb(main):007:0> a.has_key?(:key)
=> true

キーにアクセスすると、予想どおりキーが作成されます。単に has_key を尋ねるだけですか? ではない。

于 2010-04-06T01:08:51.980 に答える
9

本当に無限に深いハッシュが必要な場合:

endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
endless["deep"]["in"]["here"] = "hello"

もちろん、Glenn が上で指摘しているように、これを行うと、has_key? 常に true を返すため、意味を失います。これについては jbarnette に感謝します。

于 2010-11-23T01:03:05.130 に答える
6
irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9]                          # great!

このステートメントで、デフォルトを変更しました。新しい配列を作成して「9」を追加していません。この時点で、代わりにこれを行った場合と同じです。

irb(main):002:0> a.default = [9]
=> [9]

したがって、次のようになったとしても驚くことではありません。

irb(main):006:0> a[9]
=> [9]                          # unawesome! shouldn't this be [] ??

さらに、「<<」は配列に「9」を追加しました。それをハッシュに追加しなかったため、次のようになります。

irb(main):004:0> a
=> {}                           # ?! would have expected {8=>[9]}

.default を使用する代わりに、プログラムでおそらくやりたいことは次のようなものです。

# Time to add a new entry to the hash table; this might be 
# the first entry for this key..
myhash[key] ||= []
myhash[key] << value
于 2008-10-10T11:00:11.643 に答える
-4

これが必要かどうかはわかりませんが、不足しているハッシュキーが照会されたときに、常に空の配列を返すようにすることができます。

h = Hash.new { [] }
h[:missing]
   => []

#But, you should never modify the empty array because it isn't stored anywhere
#A new, empty array is returned every time
h[:missing] << 'entry'
h[:missing]
   => []
于 2008-10-10T18:48:24.337 に答える