Nối cặp khóa / giá trị vào băm với << trong Ruby


80

Trong Ruby, người ta có thể nối các giá trị vào các mảng hiện có bằng cách sử dụng <<:

a = []
a << "foo"

nhưng, bạn cũng có thể nối các cặp khóa / giá trị vào một hàm băm hiện có không?

h = {}
h << :key "bar"

Tôi biết bạn có thể làm:

h[:key] = ""
h[:key] << "bar"

nhưng đó không phải là tôi muốn.

Cảm ơn.


20
Tại sao không h[:key] = "bar"?
Hauleth

4
Điều này không hoạt động:h[:key] << "bar"
Chris Nielsen

Câu trả lời:


141

Có đấy merge!.

h = {}
h.merge!(key: "bar")
# => {:key=>"bar"}

3
Tôi không nghĩ rằng merge!đủ điều kiện chỉ đơn giản là tạo một cặp khóa / giá trị mới vì nó thực sự được sử dụng cho mục đích khác.
PericlesTheo

Điểm tốt. Tôi nghĩ rằng nó cũng có thể kết thúc phụ thuộc vào các yếu tố khác mà OP đã không đăng.
Michael Durrant

1
Ah, cảm ơn. Có vẻ như phương pháp cửa hàng làm điều gì đó tương tự. Đây chủ yếu là một câu hỏi học thuật như tôi đã thấy << được gọi là một cách để nối vào các mảng nhưng muốn xem liệu nó có hoạt động với hàm băm hay không. Cảm ơn một lần nữa.
jcarpio

5
Sự khác biệt là thế này: storechỉ cần thêm một cặp mới, nó không quan tâm nếu khóa đã tồn tại. với merge!tuy nhiên, mục với các phím trùng lặp được ghi đè nên phương pháp này thực hiện nhiều hơn một chút so với chỉ thêm cặp. Nếu bạn chuẩn hai, bạn sẽ tìm thấy stoređược nhanh hơn (tầm thường tuy nhiên đặc biệt là trên băm nhỏ)
PericlesTheo

2
@jcarpio Cảm ơn. Hash#merge!trả về băm bộ thu giống như Array#<<trả về mảng bộ thu. Hash#storelà một điều hoàn toàn khác. Ngoài ra, với đường cú pháp băm key: "bar"ở vị trí đối số, tôi nghĩ đây là cách gần nhất mà bạn có thể đạt được ký hiệu của mình. Tôi biết cái này gần với những gì bạn muốn.
sawa

89

Vì các hàm băm vốn dĩ không được sắp xếp theo thứ tự, nên không có khái niệm thêm vào. Tuy nhiên, các hàm băm của Ruby kể từ 1.9 vẫn duy trì thứ tự chèn. Dưới đây là các cách để thêm các cặp khóa / giá trị mới.

Giải pháp đơn giản nhất là

h[:key] = "bar"

Nếu bạn muốn một phương pháp, hãy sử dụng store:

h.store(:key, "bar")

Nếu bạn thực sự, thực sự muốn sử dụng toán tử "shovel" ( <<), thì nó thực sự đang thêm vào giá trị của hàm băm dưới dạng một mảng và bạn phải chỉ định khóa:

h[:key] << "bar"

Điều trên chỉ hoạt động khi khóa tồn tại. Để thêm một khóa mới, bạn phải khởi tạo hàm băm với một giá trị mặc định, bạn có thể làm như sau:

h = Hash.new {|h, k| h[k] = ''}
h[:key] << "bar"

Bạn có thể bị cám dỗ để Băm vá khỉ để bao gồm một toán tử xẻng hoạt động theo cách bạn đã viết:

class Hash
  def <<(k,v)
    self.store(k,v)
  end
end

Tuy nhiên, điều này không kế thừa "cú pháp đường" được áp dụng cho toán tử xẻng trong các ngữ cảnh khác:

h << :key, "bar" #doesn't work
h.<< :key, "bar" #works

Kỹ lưỡng! Cảm ơn vì sự đóng góp và cái nhìn sâu sắc.
jcarpio

Cần lưu ý, kể từ Ruby 1.9, Hashes được đặt hàng.
thép

1
Ruby 1.9+ duy trì thứ tự chèn, nhưng Hash như một cấu trúc dữ liệu không có khái niệm về bất kỳ loại trật tự vốn có nào.
Mark Thomas

27

Không, tôi không nghĩ rằng bạn có thể nối các cặp khóa / giá trị. Điều gần nhất mà tôi biết là sử dụng storephương pháp:

h = {}
h.store("key", "value")

3

Có lẽ bạn muốn hợp nhất Hash #?

1.9.3p194 :015 > h={}
 => {} 
1.9.3p194 :016 > h.merge(:key => 'bar')
 => {:key=>"bar"} 
1.9.3p194 :017 > 

Nếu bạn muốn thay đổi mảng tại chỗ merge!

1.9.3p194 :016 > h.merge!(:key => 'bar')
 => {:key=>"bar"} 

Tôi không nghĩ mergeđó là một ý tưởng hay vì nó trả về một mảng mới; không thêm cặp mới vào băm hiện có.
PericlesTheo

Làm thế nào về merge!(tức là mảng hiện có) thay vì merge?
Michael Durrant

1
merge!về mặt kỹ thuật hoạt động trong bối cảnh này nhưng tôi nghĩ nó nên được sử dụng để hợp nhất hai hàm băm thay vì chỉ đơn giản là thêm một cặp mới. Ngoài ra, nếu bạn chuẩn merge!, nó chậm hơn store;)
PericlesTheo

3

Tương tự như chúng merge!storexử lý các hàm băm hiện có khác nhau tùy thuộc vào tên khóa và do đó sẽ ảnh hưởng đến tùy chọn của bạn. Hơn thế nữa từ một quan điểm cú pháp, merge!'s key: "value"cú pháp phù hợp chặt chẽ lên chống JavaScript và Python. Cá nhân tôi luôn ghét các cặp khóa-giá trị phân tách bằng dấu phẩy.

hash = {}
hash.merge!(key: "value")
hash.merge!(:key => "value")
puts hash

{:key=>"value"}

hash = {}
hash.store(:key, "value")
hash.store("key", "value")
puts hash

{:key=>"value", "key"=>"value"}

Để người vận hành xẻng hoạt <<động, tôi khuyên bạn nên sử dụng câu trả lời của Mark Thomas .


1

Tôi đã phải làm một điều tương tự nhưng tôi cần thêm các giá trị bằng các khóa giống nhau. Khi tôi sử dụng hợp nhất hoặc cập nhật, tôi không thể đẩy các giá trị bằng các khóa giống nhau. Vì vậy, tôi đã phải sử dụng mảng băm.

    my_hash_static = {:header =>{:company => 'xx', :usercode => 'xx', :password => 'xx',
                      :type=> 'n:n', :msgheader => from}, :body=>[]}
    my_hash_dynamic = {:mp=>{:msg=>message, :no=>phones} }        
    my_hash_full = my_hash_static[:body].push my_hash_dynamic
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.