Ustawiam ruby hash.default to a list [duplicate]

To pytanie ma już odpowiedź tutaj:

Myślałem, że rozumiem, co domyślna metoda robi z Hashem...

Podaj domyślną wartość klucza, jeśli nie istnieje:

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}
Wszystko w porządku.

Ale jeśli Ustawiłem domyślną listę pustą, lub pusty hash, nie rozumiem, że to zachowanie w 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 [] ??

Miałem nadzieję / oczekiwać takiego samego zachowania, jak gdybym użył operatora//=...

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
Czy ktoś może wyjaśnić, co się dzieje?
Author: Martin Konecny, 2008-10-10

7 answers

Hash.default służy do ustawiania wartości domyślnej zwróconej , gdy odpytywasz klucz, który nie istnieje. Wpis w zbiorze nie jest tworzony dla ciebie, tylko dlatego, że go zapytałeś.

Również wartość, którą ustawiłeś default jest instancją obiektu (w Twoim przypadku tablicą), więc kiedy to zostanie zwrócone, można nią manipulować.

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
Author: Aaron Hinni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 10:48:54

Jest to bardzo przydatny idiom:

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

Może być nawet zagnieżdżony:

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

Drugą drogą jest zrobić:

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

Ale ma to znaczący efekt uboczny, że Pytanie o klucz utworzy go, który renderuje has_key? dość bezużyteczne, więc unikam tej metody.

 52
Author: glenn mcdonald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 18:02:35

Myślę, że to jest zachowanie, którego szukasz. Spowoduje to automatyczne zainicjalizowanie wszystkich nowych kluczy w haśle do tablicy:

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=>[]}
 32
Author: Turp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-11 16:39:26

Glenn mcdonald says:

"drugą drogą jest zrobić:

Myhash = Hash.new {/hash, key / hash[key] = []}

Ale ma to znaczący efekt uboczny, że pytanie o klucz go utworzy, co renderuje has_key? dość bezużyteczne, więc unikam tej metody."

Nie wydaje się to prawdą.
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

dostęp do klucza spowoduje jego utworzenie, tak jak oczekiwałem. Tylko pytasz has_key? nie.

 9
Author: jrochkind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-06 01:08:51

Jeśli naprawdę chcesz mieć nieskończenie głęboki hash:

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

Oczywiście, jak Glenn wskazuje powyżej, jeśli to zrobisz, has_key? traci swoje znaczenie, ponieważ zawsze będzie prawdziwe. Thx dla jbarnette za ten

 9
Author: migbar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-23 01:03:05
irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9]                          # great!

Za pomocą tej instrukcji zmieniłeś domyślną wartość; nie utworzyłeś nowej tablicy i dodałeś "9". W tym momencie jest to identyczne jak gdybyś zrobił to zamiast tego:

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

Stąd nic dziwnego, że teraz dostajesz to:

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

Ponadto '

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

Zamiast używać .domyślnym, co prawdopodobnie chcesz zrobić w swoim programie jest coś takiego:

# 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
Author: Simon Howard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 11:00:11

Nie jestem pewien, czy to jest to, czego chcesz, ale możesz to zrobić, aby zawsze zwracać pustą tablicę, gdy brakujący klucz hash jest pytany.

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]
   => []
 -4
Author: Daniel Beardsley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 18:48:24