2009-04-16 11 views
5

tengo un hash de rubí que tiene este aspectoCuál es la mejor manera de convertir un hash de rubí a un array

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

y quiero convertirlo en un hash que tiene este aspecto

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

También necesito preservar el orden numérico de las teclas, y hay un número variable de teclas. Lo anterior es súper simplificado, pero he incluido un ejemplo real en la parte inferior. ¿Cuál es la mejor manera de hacer esto?

PS

También tiene que ser recursivo

En cuanto a la recursividad va, esto es lo que podemos asumir:

1) la tecla que debe ser manipulado coincidirá/_attributes $/ 2) el hash tendrá muchas otras claves que no coinciden/_attributes $/ 3) las claves dentro del hash siempre serán un número 4) un _attributes hash puede estar en cualquier nivel del hash debajo de cualquier otra tecla

este hash es en realidad el hash de parámetros de una acción de creación en el controlador. Este es un ejemplo real de lo que será necesario analizar con esta rutina.

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

Respuesta

8

Tenga en cuenta que esto podría ser mucho tiempo para comprobar si todas las llaves están números antes de convertir ...

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: variable local indefinida o método 'clave 'para # \t de/storage/cait/development/app/helpers/application_helper .rb: 6: en 'array_from_hash ' –

+0

después de corregir ese error cambiando la clave k.to_i.to_s == por k.to_i.to_s == k, ¡funciona correctamente! ¡Gracias! –

+0

Tienes algunas ideas interesantes para sangrar aquí :) – rfunduk

4

Si podemos suponer que todas las llaves están en cadenas de datos que convierten limpiamente a números enteros, el siguiente debe trabajar;

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

¿cómo puedo hacer esto recursivamente? Me olvidé de mencionar eso en la pregunta: \ –

+0

¿Podría darme un ejemplo de cómo se podría armar la estructura completa? ¿Qué tan profunda debe ir la recursión, y cómo podemos diferenciar entre los hash que deben convertirse y los hashes que no (como el inner {"foo" => "bar", "baz" => "quux" })? –

+0

agregó algunas reglas más en la parte inferior de la pregunta, thx para ayudar :) –

0

Para tomar un poco de libertad, estoy publicando un ejemplo de código muy similar a Vincent Robert's.

Este es parches de la clase Hash con un método .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 

Hace que el uso sea un poco más conveniente.

Cuestiones relacionadas