2009-04-16 6 views
5

J'ai un hachage rubis qui ressemble à cecice qui est la meilleure façon de convertir un hachage rubis à un tableau

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

et je veux en faire un hachage qui ressemble à ceci

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

J'ai aussi besoin de préserver l'ordre numérique des touches, et il y a un nombre variable de clés. Ce qui précède est super-simplifié, mais j'ai inclus un exemple réel en bas. Quelle est la meilleure façon de faire cela?

PS

Il doit également être récursive

En ce qui concerne la récursion va, voici ce que nous pouvons supposer:

1) la clé qui doit être manipulé détectera/_attributes $/ 2) le hachage aura beaucoup d'autres clés qui ne correspondent pas/_attributs $/3) les clés à l'intérieur du hachage seront toujours un nombre 4) un hachage _attributes peut être à n'importe quel niveau du hachage sous toute autre clé

ce hachage est en fait le hachage params d'une action de création dans le contrôleur. Ceci est un exemple réel de ce qui devra être analysé avec cette routine.

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

Répondre

8

Notez que cela pourrait être long pour vérifier si toutes les clés sont numéros avant la conversion ...

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 locale non définie ou méthode 'key 'pour # \t de/storage/cait/développement/app/helpers/application_helper .rb: 6: dans 'array_from_hash ' –

+0

après avoir corrigé cette erreur en changeant k.to_i.to_s == clé de k.to_i.to_s == k, cela fonctionne parfaitement! Merci! –

+0

Vous avez des idées intéressantes ici indentation :) – rfunduk

4

Si nous pouvons supposer que toutes les clés sont dans les chaînes d'information qui convertissent proprement aux entiers, les éléments suivants devraient fonctionner:

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

Comment est-ce que je peux le faire récursivement? J'ai oublié de mentionner cela dans la question: \ –

+0

Pourriez-vous donner un exemple des façons dont la structure complète pourrait être mise en place? Quelle est la profondeur de la récursion, et comment pouvons-nous différencier les hachages qui doivent être convertis et les hachages qui ne le sont pas (comme le {"foo" => "bar", "baz" => "quux" })? –

+0

ajouté quelques règles plus au fond de la question, thx pour aider :) –

0

pour prendre un peu d'une liberté, je poste un exemple de code très similaire à Vincent de Robert.

Celui-ci corrige la classe Hash avec une méthode .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 

Il rend l'utilisation légèrement plus pratique.

Questions connexes