web-dev-qa-db-ja.com

Ruby hash .default to alist

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

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

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}

すべて良い。

しかし、デフォルトを空のリストまたは空のハッシュに設定した場合、all ...での動作がわかりません。

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

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

40
mat kelcey

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

また、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
49
Aaron Hinni

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

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

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

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

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

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

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

52
glenn mcdonald

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

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=>[]}
33
Turp

グレンマクドナルドは言う:

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

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

しかし、これには重大な副作用があり、キーについて尋ねるとキーが作成され、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を尋ねるだけですか?ではない。

9
jrochkind

あなたが本当に無限に深いハッシュを持ちたいのなら:

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

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

9
migbar
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
6
Simon Howard