2009-04-16 28 views
5

Tôi có một băm ruby ​​trông như thế nàycách tốt nhất để chuyển đổi một băm ruby ​​để một mảng

{ "stuff_attributes" => { 
    "1" => {"foo" => "bar", "baz" => "quux"}, 
    "2" => {"foo" => "bar", "baz" => "quux"} 
    } 
} 

là những gì và tôi muốn biến nó thành một hash trông như thế này

{ "stuff_attributes" => [ 
    { "foo" => "bar", "baz" => "quux"}, 
    { "foo" => "bar", "baz" => "quux"} 
    ] 
} 

Tôi cũng cần giữ lại thứ tự số của các phím và có một số lượng khóa thay đổi. Ở trên là siêu đơn giản, nhưng tôi đã bao gồm một ví dụ thực tế ở phía dưới. Cách tốt nhất để làm điều này là gì?

PS

Nó cũng cần phải được đệ quy

Theo như các đệ quy đi, đây là những gì chúng ta có thể giả định:

1) chìa khóa mà cần phải được thao tác sẽ phù hợp/_attributes $/ 2) băm sẽ có nhiều khóa khác không khớp/_attributes $/ 3) các khóa bên trong băm sẽ luôn là số 4) băm _attributes có thể ở bất kỳ mức băm nào dưới bất kỳ khóa nào khác

băm này thực sự là băm params từ một hành động tạo trong bộ điều khiển. Đây là một ví dụ thực sự về những gì sẽ cần phải được phân tích cú pháp với thói quen này.

{ 
    "commit"=>"Save", 
    "tdsheet"=>{ 
    "team_id"=>"43", 
    "title"=>"", 
    "performing_org_id"=>"10", 
    "tdsinitneed_attributes"=>{ 
     "0"=>{ 
      "title"=>"", 
      "need_date"=>"", 
      "description"=>"", 
      "expected_providing_organization_id"=>"41" 
      }, 
     "1"=>{ 
      "title"=>"", 
      "need_date"=>"", 
      "description"=>"", 
      "expected_providing_organization_id"=>"41" 
      } 
     }, 
     "level_two_studycollection_id"=>"27", 
     "plan_attributes"=>{ 
      "0"=>{ 
       "start_date"=>"", "end_date"=>"" 
      } 
     }, 
     "dataitem_attributes"=>{ 
      "0"=>{ 
       "title"=>"", 
       "description"=>"", 
       "plan_attributes"=>{ 
        "0"=>{ 
         "start_date"=>"", 
         "end_date"=>"" 
         } 
        } 
       }, 
      "1"=>{ 
       "title"=>"", 
       "description"=>"", 
       "plan_attributes"=>{ 
        "0"=>{ 
         "start_date"=>"", 
         "end_date"=>"" 
         } 
        } 
       } 
      } 
     }, 
    "action"=>"create", 
    "studycollection_level"=>"", 
    "controller"=>"tdsheets" 
} 

Trả lời

8

Lưu ý rằng đây có thể là thời gian để kiểm tra xem tất cả các phím các số trước khi chuyển đổi ...

def array_from_hash(h) 
    return h unless h.is_a? Hash 

    all_numbers = h.keys.all? { |k| k.to_i.to_s == k } 
    if all_numbers 
    h.keys.sort_by{ |k| k.to_i }.map{ |i| array_from_hash(h[i]) } 
    else 
    h.each do |k, v| 
     h[k] = array_from_hash(v) 
    end 
    end 
end 
+0

NameError: biến không xác định cục bộ hoặc phương thức 'khóa 'cho # \t từ/storage/cait/development/app/helpers/application_helper .rb: 6: trong 'mảng_from_hash ' –

+0

sau khi sửa lỗi đó bằng cách thay đổi khóa k.to_i.to_s == thành k.to_i.to_s == k, nó hoạt động đúng đắn! cảm ơn! –

+0

Bạn đã có một số ý tưởng thú vị wrt indenting ở đây :) – rfunduk

4

Nếu chúng ta có thể giả định rằng tất cả các phím trong chuỗi thực tế mà chuyển đổi sạch để nguyên, sau đây nên làm việc:

# "hash" here refers to the main hash in your example, since you didn't name it 
stuff_hash = hash["stuff"] 
hash["stuff"] = stuff_hash.keys.sort_by {|key| key.to_i}.map {|key| stuff_hash[key]} 
+0

làm cách nào tôi có thể thực hiện điều này một cách đệ quy? Tôi quên đề cập rằng trong câu hỏi: \ –

+0

Bạn có thể cung cấp một ví dụ về cách cấu trúc đầy đủ có thể được đặt lại với nhau không? Làm thế nào sâu đệ quy cần phải đi, và làm thế nào chúng ta có thể phân biệt giữa băm cần phải được chuyển đổi và băm mà không (chẳng hạn như bên trong {"foo" => "bar", "baz" => "quux" })? –

+0

thêm một số quy tắc khác ở cuối câu hỏi, thx để được trợ giúp :) –

0

Để có chút tự do, tôi đăng một ví dụ mã rất giống với Vincent Robert.

Cái này là bản vá của lớp Hash với phương thức .to_array.

class Hash 
    def to_array(h = self) 
    return h unless h.is_a? Hash 
    if h.keys.all? { |k| k.to_i.to_s == k } # all keys are numbers so make an array. 
     h.keys.sort_by{ |k| k.to_i }.map{ |i| self.to_array(h[i]) } 
    else 
     h.each do |k, v| 
     h[k] = self.to_array(v) 
     end 
    end 
    end 
end 

Nó giúp việc sử dụng thuận tiện hơn một chút.

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