2011-03-30 35 views
8

Tôi đã thêm các mục vào khóa băm. Tôi đã mong đợi để có được một cấu trúc như thế này:Không thể sử dụng mảng làm giá trị mặc định cho Ruby Hash?

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

Tôi đã sử dụng một mảng để khởi tạo băm.

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

Sau đó, bắt đầu sử dụng nó:

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

Nhưng nó quay ra:

irb> hash 
=> {} 
+0

Bạn có chắc chắn về kết quả bạn đang xem không? Hoặc những gì Hash thực sự chứa? Không rõ bạn đang tìm gì ở đây. – jmccarthy

Trả lời

11

Hãy thử như sau thay vì:

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

Lý do bạn nhận được kết quả bất ngờ của bạn là bạn chỉ định một mảng trống làm giá trị mặc định, nhưng cùng một mảng được sử dụng; không sao chép được thực hiện. Cách đúng là để khởi tạo giá trị với một mảng trống mới, như trong mã của tôi.

+0

+1 "bạn đã chỉ định một mảng trống làm giá trị mặc định, nhưng cùng một mảng được sử dụng". Chơi lô tô! –

+0

Cái gì ?! Điều này thực sự lạ với tôi. Khi bạn sử dụng chuỗi, chuỗi đó sẽ không được sử dụng lại. Chuỗi có thể là loại giá trị nào đó, nhưng tôi nghĩ "mọi thứ" là một đối tượng trong Ruby. Tại sao sự khác biệt giữa các chuỗi và các đối tượng khác? – Automatico

+0

@ Cort3z: Không chắc chắn ý của bạn là gì. Có lẽ điều này có thể giúp cho thấy không có sự khác biệt: 'a = b = 'foo'; a.replace 'bar'; b # => 'bar'' –

2

hash['a'] << 1hash['b'] << 2 không phải là cú pháp chính xác để tạo một cặp khóa/giá trị. Bạn phải sử dụng = cho rằng:

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

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

Điều đó sẽ cung cấp cho bạn các hash {'a' : [1], 'b' : [2]}

4

constructor bạn đã sử dụng cửa hàng [] làm giá trị mặc định để trả lại khi truy cập các khóa chưa xác định. Kể từ khi Array#<< sửa đổi máy thu tại chỗ mảng trống ban đầu này phát triển.

Để giải thích chi tiết hơn:

Khi bạn làm hash['a'] << 1 đây là những gì sẽ xảy ra:

  1. hash trông để xem nếu có một khóa có tên 'a'
  2. nó tìm thấy rằng không có, có không có khóa như vậy.
  3. Có vẻ như nó đã lưu trữ giá trị mặc định để trả lại.
  4. Vì bạn đã xây dựng nó với Hash.new([]), nó có giá trị như vậy, [] và nó trả về điều đó.
  5. Bây giờ [] << 1 được đánh giá và điều này có nghĩa là băm hiện đang lưu trữ [1] làm giá trị trả lại khi khóa không được gặp trước đó được yêu cầu.

Nếu những gì bạn muốn là để lưu trữ các cặp giá trị key thay vì sử dụng các hình thức thứ ba của các nhà xây dựng với một khối:

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

Đây là chính xác hành vi mà bạn mong đợi để xem.

Bạn không bao giờ thêm bất kỳ thứ gì vào số Hash, do đó, Hash hoàn toàn trống. Khi bạn tra cứu một khóa, khóa đó sẽ không bao giờ tồn tại, do đó nó trả về giá trị mặc định, mà bạn đã chỉ định là một Array.

Vì vậy, bạn tra cứu khóa 'a', không tồn tại và do đó trả về giá trị mặc định là Array. Sau đó, bạn gọi số << trên số đó Array, gắn thêm một giá trị (1) vào đó.

Tiếp theo, bạn tra khóa 'b', cũng không tồn tại, và do đó trả về Array bạn đã chỉ định làm giá trị mặc định, hiện chứa phần tử 1 mà bạn đã thêm trước đó. Sau đó, bạn gọi số << trên số đó Array, thêm giá trị 2 vào đó.

Bạn kết thúc bằng số Hash vẫn còn trống, vì bạn chưa bao giờ thêm bất kỳ thứ gì vào đó. Giá trị mặc định của Hash hiện là một mảng chứa các giá trị 12.

Kết quả bạn thấy là bởi vì IRB luôn in kết quả của biểu thức cuối cùng được đánh giá. Biểu thức cuối cùng trong ví dụ của bạn là gọi << trên Array. << trả về bộ thu, sau đó là giá trị trả về của toàn bộ biểu thức và do đó IRB in ra.

+0

+1 Độc đáo nói. –

+0

Nó thực hiện chính xác những gì bạn hỏi, và không phải tất cả những gì bạn có ý nghĩa! –

Các vấn đề liên quan