Rails ánh xạ mảng băm vào một băm duy nhất


91

Tôi có một mảng các hàm băm như vậy:

 [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]

Và tôi đang cố gắng ánh xạ điều này thành một hàm băm đơn như thế này:

{"testPARAM2"=>"testVAL2", "testPARAM1"=>"testVAL1"}

Tôi đã đạt được nó bằng cách sử dụng

  par={}
  mitem["params"].each { |h| h.each {|k,v| par[k]=v} } 

Nhưng tôi đã tự hỏi liệu có thể làm điều này theo cách dễ hiểu hơn không (tốt nhất là không sử dụng biến cục bộ).

Tôi có thể làm cái này như thế nào?

Câu trả lời:


159

Bạn có thể sáng tác Enumerable#reduceHash#mergehoàn thành những gì bạn muốn.

input = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
input.reduce({}, :merge)
  is {"testPARAM2"=>"testVAL2", "testPARAM1"=>"testVAL1"}

Giảm một loại mảng giống như gắn một lệnh gọi phương thức giữa mỗi phần tử của nó.

Ví dụ [1, 2, 3].reduce(0, :+)giống như nói 0 + 1 + 2 + 3và cho 6.

Trong trường hợp của chúng tôi, chúng tôi làm điều gì đó tương tự, nhưng với hàm hợp nhất, hợp nhất hai hàm băm.

[{:a => 1}, {:b => 2}, {:c => 3}].reduce({}, :merge)
  is {}.merge({:a => 1}.merge({:b => 2}.merge({:c => 3})))
  is {:a => 1, :b => 2, :c => 3}

1
Cảm ơn, đây là một câu trả lời tuyệt vời :) Giải thích rất độc đáo!
Bart Platak

40
input.reduce (&: merge) là đủ.
redgetan

@redgetan có gì khác với input.reduce(:merge)?
David van Geest

1
@David van Geest: Trong trường hợp này, chúng tương đương nhau. Ký hiệu đơn phân và như được sử dụng ở đây xây dựng một khối ra khỏi biểu tượng. Tuy nhiên, giảm có một trường hợp đặc biệt chấp nhận một ký hiệu. Tôi muốn tránh toán tử dấu và một bậc để đơn giản hóa ví dụ, nhưng redgetan đúng rằng giá trị ban đầu là tùy chọn trong trường hợp này.
cjhveal

1
Lưu ý rằng nếu bạn sử dụng merge!thay vì mergenó sẽ sửa đổi hàm băm đầu tiên (mà bạn có thể không muốn) nhưng sẽ không tạo hàm băm trung gian cho mỗi lần hợp nhất mới.
Phrogz

50

Làm thế nào về:

h = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
r = h.inject(:merge)

Lược đồ này tương tự như những gì Joshua đã trả lời, nhưng liên tục áp dụng #merge (tên phương thức được truyền dưới dạng ký hiệu) trên tất cả các hàm băm (hãy nghĩ đến việc tiêm giống như việc tiêm toán tử giữa các mục). Tham khảo #inject .
shigeya

2
Tại sao chúng ta không cần ký hiệu và, như trong h.inject (&: merge)?
Donato

5
Bởi vì phương thức tiêm chấp nhận một biểu tượng làm tham số cũng được hiểu là tên phương thức. Đó là tính năng của tiêm.
shigeya

9

Sử dụng #inject

hashes = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
merged = hashes.inject({}) { |aggregate, hash| aggregate.merge hash }
merged # => {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}

0

Ở đây bạn có thể sử dụng bơm hoặc giảm từ Enumerable lớp như cả hai trong số đó là bí danh của nhau nên không có hiệu quả lợi ích cho một trong hai.

 sample = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]

 result1 = sample.reduce(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}

 result2 = sample.inject(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
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.