Подтвердить что ты не робот

Установка рубинового хэша .default в список

Я думал, что понял, что метод по умолчанию делает с хешем...

Дайте значение по умолчанию для ключа, если оно не существует:

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

Кто-нибудь может объяснить, что происходит?

4b9b3361

Ответ 1

Hash.default используется для установки значения по умолчанию возвращено при запросе ключа, который не существует. Запись в коллекции не создана для вас, просто потому, что она запросила его.

Кроме того, значение, которое вы установили default to, является экземпляром объекта (массив в вашем случае), поэтому, когда это возвращается, его можно манипулировать.

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

Ответ 2

Это очень полезная идиома:

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

Он может быть даже вложенным:

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

Другой способ:

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

Но это имеет существенный побочный эффект, который запрашивает о ключе, создаст его, что делает has_key? бесполезно, поэтому я избегаю этого метода.

Ответ 3

Я думаю, что это то поведение, которое вы ищете. Это автоматически инициализирует любые новые ключи в Hash для массива:

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

Ответ 4

glenn mcdonald говорит:

"Другой способ:

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? не.

Ответ 5

Если вы действительно хотите иметь бесконечный глубокий хеш:

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

Конечно, как указывает Гленн выше, если вы это сделаете, has_key? теряет свой смысл, поскольку он всегда будет возвращать истину. спасибо для jbarnette для этого.

Ответ 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

Ответ 7

Я не уверен, что это то, что вы хотите, но вы можете сделать это, чтобы всегда возвращать пустой массив, когда запрашивается отсутствующий хэш-ключ.

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]
   => []