2011-03-30 10 views
8

Dodawałem elementy do klucza skrótu. Spodziewałem się uzyskać taką strukturę:Nie można użyć tablicy jako wartości domyślnych dla Ruby Hash?

{ 
    'a' : [1], 
    'b' : [2, 3, 4] 
} 

Użyłem tablicy do zainicjowania skrótu.

irb> hash = Hash.new([]) 
=> {} 

Potem zaczął używać go:

irb> hash['a'] << 1 
=> [1] 
irb> hash['b'] << 2 
=> [1, 2] 

Ale okazuje się:

irb> hash 
=> {} 
+0

Nie masz pewności, jakie dane wyjściowe widzisz? Albo co właściwie zawiera Hash? Nie jest jasne, czego tu szukasz. – jmccarthy

Odpowiedz

11

Spróbuj następujące zamiast:

hash = Hash.new{|h, k| h[k] = []} 
hash['a'] << 1 # => [1] 
hash['b'] << 2 # => [2] 

powód, dla którego masz swoje nieoczekiwane rezultaty jest podałeś pusta tablica jako wartość domyślna, ale używana jest ta sama tablica; żadna kopia nie została wykonana. Właściwą drogą jest zainicjowanie wartości za pomocą nowej pustej tablicy, tak jak w moim kodzie.

+0

+1 "podałeś pustą tablicę jako wartość domyślną, ale używana jest ta sama tablica". Bingo! –

+0

Co ?! To dla mnie naprawdę dziwne. Kiedy używasz łańcucha, którego ciąg nie jest ponownie używany. Łańcuch może być pewnego rodzaju typem wartości, ale myślałem, że "wszystko" jest obiektem w Ruby. Dlaczego różnica między łańcuchami i innymi obiektami? – Automatico

+0

@ Cort3z: Nie jestem pewien co masz na myśli. Może to pomoże pokazać, że nie ma różnicy: 'a = b = 'foo'; a.replace 'bar'; b # => 'bar'' –

2

hash['a'] << 1 i hash['b'] << 2 nie jest poprawna składnia do tworzenia pary klucz/wartość. Musisz użyć = za to:

hash['a'] = [] 
hash['a'] << 1 

hash['b'] = [] 
hash['b'] << 2 

To powinno dać ci hash {'a' : [1], 'b' : [2]}

4

Użytkownik używał constructor jako domyślnej wartości do zwracania podczas uzyskiwania dostępu do kluczy, które są nieznane. Od Array#<< modyfikuje swój odbiornik w miejsce ta początkowo pusta tablica rośnie.

Aby wyjaśnić bardziej szczegółowo:

Kiedy robisz hash['a'] << 1 to, co się dzieje:

  1. hash sprawdza, czy istnieje klucz o nazwie 'a'
  2. stwierdzi, że nie istnieje nie ma takiego klucza.
  3. Wygląda na to, że zapisał domyślną wartość do zwrócenia.
  4. Od czasu skonstruowania go z Hash.new([]) ma taką wartość, [] i zwraca to.
  5. Teraz jest oceniany [] << 1, co oznacza, że ​​hash przechowuje teraz [1] jako wartość, którą należy zwrócić, gdy zażądano wcześniej niezarejestrowanego klucza.

Jeśli to, co chcesz, aby zapisać parę kluczy wartości zamiast użyć trzecią postać konstruktora z bloku:

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

To dokładnie zachowanie, że można oczekiwać, aby zobaczyć.

Nigdy nie dodajesz niczego do Hash, dlatego Hash jest całkowicie pusty. Podczas wyszukiwania klucza klucz ten nigdy nie istnieje, dlatego zwraca wartość domyślną, którą określono jako Array.

Sprawdzasz klucz 'a', który nie istnieje, a tym samym zwraca wartość Array, którą podałeś jako wartość domyślną. Następnie należy wywołać << na tym Array, który dodaje do niego wartość (1).

Następnie należy wyszukać klucz 'b', który również nie istnieje, a następnie zwraca podaną wartość domyślną, która zawiera teraz dodany wcześniej element 1. Następnie wywołujesz << na tym Array, dołączając do niego wartość 2.

Kończysz z Hash, który jest wciąż pusty, ponieważ nigdy nie dodałeś do niego niczego. Domyślna wartość Hash jest teraz tablicą zawierającą wartości 1 i 2.

Dane wyjściowe, które widzisz, są takie, że IRb zawsze drukuje wynik ostatniego wyrażenia, które zostało ocenione. Ostatnie wyrażenie w twoim przykładzie wywołuje << na Array. << zwraca jego odbiornik, który następnie jest wartością zwracaną całego wyrażenia, a tym samym, co drukuje IRb.

+0

+1 Ładnie powiedział. –

+0

Wykonuje dokładnie to, o co prosisz, a nie o to, co masz na myśli! –

Powiązane problemy