2009-04-16 10 views
5

mam hash rubinowy, który wygląda takjaki jest najlepszy sposób przekonwertować hash rubinowy do tablicy

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

i chcę, aby przekształcić go w haszyszu, który wygląda tak

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

Muszę również zachować porządek numeryczny kluczy i istnieje zmienna liczba kluczy. Powyższe jest super uproszczone, ale dodałem prawdziwy przykład na dole. Jaki jest najlepszy sposób na zrobienie tego?

PS

Musi także być rekurencyjne

Jeśli chodzi o rekurencji idzie, oto co możemy założyć:

1) kluczem, który musi być manipulowane będzie pasował/_attributes $/ 2) hash będzie miał wiele innych kluczy, które nie pasują/_attributes $/ 3) klucze wewnątrz skrótu będą zawsze mieć numer 4) asocjacja _attributes może znajdować się na dowolnym poziomie skrótu pod dowolnym innym kluczem

ten skrót jest w rzeczywistości hash params od akcji tworzenia w kontrolerze. To jest prawdziwy przykład tego, co trzeba będzie sparsować z tą procedurą.

{ 
    "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" 
} 

Odpowiedz

8

Zauważ, że to może być długi, aby sprawdzić, czy wszystkie klawisze są numery przed konwersją ...

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: niezdefiniowana zmienna lokalna lub metoda 'key 'dla # \t from/storage/cait/development/app/helper/application_helper .rb: 6: w 'array_from_hash ' –

+0

po naprawieniu tego błędu poprzez zmianę klucza k.to_i.to_s == na k.to_i.to_s == k, działa perfekcyjnie! dzięki! –

+0

Masz kilka ciekawych pomysłów na wcięcie tutaj :) – rfunduk

4

Jeśli możemy założyć, że wszystkie klucze są w rzeczywistości strun, które przekształcają czysto do liczb całkowitych, następujące powinny działać:

# "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

Jak mogę to zrobić rekurencyjnie? Zapomniałem wspomnieć o tym w pytaniu: \ –

+0

Czy możesz podać przykład sposobu, w jaki można ułożyć całą strukturę? Jak głęboka musi być rekursja i jak możemy rozróżnić skróty, które muszą zostać przekonwertowane, i niepoprawne (np. Wewnętrzny {"foo" => "bar", "baz" => "quux" })? –

+0

dodał kilka reguł na dole pytania, thx za pomoc :) –

0

wziąć kawałek wolności, jestem delegowania bardzo podobny przykład kodu do Vincent Roberta.

To jest łatka klasy Hash z metodą Hash za pomocą metody .

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 

Sprawia, że ​​korzystanie jest nieco wygodniejsze.

Powiązane problemy