2017-10-09 1 views
1

Censé J'ai un tableau qui ressembleConversion d'un tableau de hachage en Ruby

testarr = [["Actor", "Morgan", "33", ["A","B"]], 
    ["Movie", "Titanic", "44", ["A","A"]], 
    ["Actor", "Jack Black", "333", ["A","A"]]] 

Je veux convertir en une table de hachage qui sera transformé en JSON éventuellement.

Je veux qu'il ressemble

{ 

    "Actor" => { 
      { "name" : "Morgan", 
       "Age" : 33", 
       "Films: { "A", "B" }} , 

      { "name" : "Jack Black", 
       "Age" : 44", 
       "Films: { "A", "A" }} 
      } 
    "Movie" => { 
      { "Title" : "Titanic" 
       "Gross" : "44" 
       "Actors" : { "A", "A" } 
      } 
    } 

ne suis pas sûr du format exact, mais ce qui est logique.

J'ai essayé

def hashing(arr) 
hash = Hash.new 

arr.each do |item| 

    if item[0] == "Movie" 
     item.delete("Movie") 
     hash["Movie"] = item 
     item["Title"] = item[1] 
     item["Movie"]["Box Office"] = item[2] 
     item["Movie"]["Actors"] = item[3] 

    else 

     item.delete("Actor") 
     hash["Actor"] = item 

     item["Actor"]["Name"] == item[1] 
     item["Actor"]["Age"] == item[2] 
     item["Actor"]["Filmography"] == item[3] 

    end 

    end 

    return hash 

end 

testarr = [["Actor", "Morgan", "33", ["dsfds","dsfdsf"]], 
    ["Movie", "Titanic", "44", ["dsfds","dfdsf"]], 
    ["Actor", "Jack Black", "333", ["ssdsfds","dsfdsf"]]] 

puts hashing(testarr) 

Mais il me donne une erreur de mettre l'élément de tableau dans « Film » et « Acteur », puis essayer de créer des clés comme « Nom » et « âge ».

Comment puis-je faire cela comme je le désire?

Répondre

1
testarr = [["Actor", "Morgan", "33", ["A","B"]], 
    ["Movie", "Titanic", "44", ["A","A"]], 
    ["Actor", "Jack Black", "333", ["A","A"]]] 

    a = Hash.new{ |h,k| h[k] = [] } 

    testarr.each do |arr| 
    b = {name: arr[1], age: arr[2], films: arr[3]} 
    a[arr[0]] << b 
    end 

cela produira

{"Actor"=>[{"name"=>"Morgan", "age"=>"33", "films"=>["A", "B"]}, {"name"=>"Jack Black", "age"=>"333", "films"=>["A", "A"]}], "Movie"=>[{"name"=>"Titanic", "age"=>"44", "films"=>["A", "A"]}]} 
+0

Merci. Comment puis-je mettre l'âge et la filmographie d'un acteur dans la clé de nom? Comme nom => Morgan => {Âge: 33, Filmo = [...]} – user6792790

1

S'il vous plaît essayez le code ci-dessous,

v = [["Actor", "Morgan", "33", ["A", "B"]], ["Movie", "Titanic", "44", ["A", "A"]], ["Actor", "Jack Black", "333", ["A", "A"]]] 

v.inject({}) do |ot, arr| 
    item = {name: arr[1], age: arr[2], films: arr[3]} 
    if ot[arr[0]].present? 
    ot[arr[0]] << item 
    else 
    ot[arr[0]] = [] 
    ot[arr[0]] << item 
    end 
    ot 
end 

Et o/p est comme ci-dessous,

# => {"Actor"=>[{:name=>"Morgan", :age=>"33", :films=>["A", "B"]}, {:name=>"Jack Black", :age=>"333", :films=>["A", "A"]}], "Movie"=>[{:name=>"Titanic", :age=>"44", :films=>["A", "A"]}]} 

S'il vous plaît noter ici le Acteur n'est pas hachage de hachages, il est un tableau de hachages , ceci est la manière standard de conserver la collection et de la convertir en json si vous en avez besoin en utilisant la méthode to_json.

+0

Merci! Mais je reçois une méthode indéfinie 'présent? ' pour nil: NilClass (NoMethodError). Est-ce une méthode valide? – user6792790

+0

Oui, c'est la méthode standard de rails. Utilisez-vous Rails ou non? – Mohanraj

+0

J'utilise régulièrement ruby ​​ – user6792790

1

Vous devez parcourir le tableau et analyser chaque élément, ajoutant à la valeur de hachage résultante.

testarr = [["Actor", "Morgan", "33", ["A", "B"]], 
      ["Movie", "Titanic", "44", ["A", "A"]], 
      ["Actor", "Jack Black", "333", ["A", "A"]]] 

results = {} 

testarr.each do |item| 
    key, a, b, c = item 
    r = if key == 'Actor' 
     { name: a, age: b, movies: c } 
     elsif key == 'Movie' 
     { title: a, gross: b, actors: c } 
     end 
    results[key] = [] unless results[key] 
    results[key] << r 
end 

puts results 

Cela produira:

{"Actor"=>[{:name=>"Morgan", :age=>"33", :movies=>["A", "B"]}, {:name=>"Jack Black", :age=>"333", :movies=>["A", "A"]}], "Movie"=>[{:title=>"Titanic", :gross=>"44", :actors=>["A", "A"]}]} 
1

La valeur de votre :actor contient un hachage sans clé. La meilleure chose que vous pouvez faire est de mettre cela dans un tableau.

Cela fonctionnera. Il pourrait y avoir un moyen plus propre, mais je ne sais pas comment au moment:

h = Hash.new { |hash, key| hash[key] = [] } 
testarr = [["Actor", "Morgan", "33", ["A", "B"]], ["Movie", "Titanic", "44", ["A", "A"]], ["Actor", "Jack Black", "333", ["A", "A"]]] 

testarr.each do |t| 
    if t[0] == 'Movie' 
    h[t[0]] << {title: t[1], gross: t[2], actors: t[3]} 
    else 
    h[t[0]] << {name: t[1], age: t[2], films: t[3]} 
    end 
end 

puts h 

Sortie:

{"Actor"=>[{:name=>"Morgan", :age=>"33", :films=>["A", "B"]}, {:name=>"Jack Black", :age=>"333", :films=>["A", "A"]}], "Movie"=>[{:title=>"Titanic", :gross=>"44", :actors=>["A", "A"]}]} 
+0

Merci. Comment puis-je mettre l'âge et la filmographie d'un acteur dans la clé de nom? Comme nom => Morgan => {Âge: 33, Filmo = [...]} – user6792790

1

J'ai essayé de garder l'exemple que vous avez écrit.

D'abord, il doit être mis en forme pour Array (tels que [a, b]) ne Hash ({a, b}) liste des articles

# You may want result like this ... 
{ 
    "Actor": [ # not '{' but '[' 
     { 
      "name": "Morgan", 
      "Age": "33", 
      "Films": ["A", "B"] # not '{' but '[' also 
     }, 
     { 
      "name": "Jack Black", 
      "Age": "44", 
      "Films": ["A", "A"] 
     } 
    ], 
    "Movie": [ 
     { 
      "Title": "Titanic", 
      "Gross": "44", 
      "Actors": ["A", "A"] 
     } 
    ] 
} 

et votre fonction devrait être comme ça ...

def hashing(arr) 
    hash = Hash.new 
    hash["Movie"], hash["Actor"] = [], [] 

    arr.each do |item| 

     if item[0] == "Movie" 
      movie = {} 
      movie["Title"]  = item[1] 
      movie["Box Office"] = item[2] 
      movie["Actors"]  = item[3] 

      item.delete("Movie")   # optional 
      hash["Movie"] << movie 

     else 
      actor = {} 
      actor["Name"]   = item[1] 
      actor["Age"]   = item[2] 
      actor["Filmography"] = item[3] 

      item.delete("Actor")   # optional 
      hash["Actor"] << actor 
     end 

    end 

    return hash 
end 

Ensuite, il est temps de tester! que vos codes,

testarr = [ 
    ["Actor", "Morgan", "33", ["dsfds","dsfdsf"]], 
    ["Movie", "Titanic", "44", ["dsfds","dfdsf"]], 
    ["Actor", "Jack Black", "333", ["ssdsfds","dsfdsf"]] 
] 

puts hashing(testarr) 

Il retournera ceci:

{ 
    "Movie"=> 
    [ 
     {"Title"=>"Titanic", "Box Office"=>"44", "Actors"=>["dsfds", "dfdsf"]} 
    ], 
    "Actor"=> 
    [ 
     {"Name"=>"Morgan", "Age"=>"33", "Filmography"=>["dsfds", "dsfdsf"]}, 
     {"Name"=>"Jack Black", "Age"=>"333", "Filmography"=>["ssdsfds", "dsfdsf"]} 
    ] 
} 
+0

Merci. Comment puis-je mettre l'âge et la filmographie d'un acteur dans la clé de nom? Comme Name => Morgan => {Age: 33, Filmo = [...]} – user6792790

+0

Simple! Enveloppez votre structure une fois de plus. Dans votre expression, 'Name => Morgan => {...}' va avec wrapper comme 'Name => {Morgan => {...}}'. Toutes vos clés dans la structure, doivent avoir une structure entière pour la valeur, comme ce que j'emballe. En passant, je suggère un original plutôt qu'un nouveau pour protéger et définir les objets plus clairement. –

0

code

def convert(arr, keys) 
    arr.group_by(&:first).transform_values do |a| 
    a.map { |key, *values| keys[key].zip(values).to_h } 
    end 
end 

Exemple (en utilisant testarr défini dans la question)

keys = { "Actor"=>[:name, :Age, :Films], "Movie"=>[:Title, :Gross, :Actors] } 

convert(testarr, keys) 
    #=> { "Actor"=>[ 
    #  {:name=>"Morgan", :Age=>"33", :Films=>["A", "B"]}, 
    #  {:name=>"Jack Black", :Age=>"333", :Films=>["A", "A"]} 
    #  ], 
    #  "Movie"=>[ 
    #  {:Title=>"Titanic", :Gross=>"44", :Actors=>["A", "A"]} 
    #  ] 
    # } 

Explication

Voir Enumerable#group_by, Hash#transform_values, Array#zip et Array#to_h.

Les étapes sont les suivantes.

h = testarr.group_by(&:first) 
    #=> { "Actor"=>[ 
    #  ["Actor", "Morgan", "33", ["A", "B"]], 
    #  ["Actor", "Jack Black", "333", ["A", "A"]] 
    #  ], 
    #  "Movie"=>[ 
    #  ["Movie", "Titanic", "44", ["A", "A"]] 
    #  ] 
    # } 

Bien que pas tout à fait équivalent, vous pouvez penser à testarr.group_by(&:first) comme « raccourci » pour testarr.group_by { |a| a.first }. En continuant,

e0 = h.transform_values 
    #=> #<Enumerator: 
    # {"Actor"=>[["Actor", "Morgan", "33", ["A", "B"]], 
    #    ["Actor", "Jack Black", "333", ["A", "A"]]], 
    # "Movie"=>[["Movie", "Titanic", "44", ["A", "A"]]]} 
    # :transform_values> 

Le premier élément est engendré par l'énumérateur e0, passé au bloc et la variable de bloc est égale à cette valeur.

a = e0.next 
    #=> [["Actor", "Morgan", "33", ["A", "B"]], 
    # ["Actor", "Jack Black", "333", ["A", "A"]]] 

Un deuxième énumérateur est maintenant créé.

e1 = a.map 
    #=> #<Enumerator: [["Actor", "Morgan", "33", ["A", "B"]], 
    #     ["Actor", "Jack Black", "333", ["A", "A"]]]:map> 

La première valeur est générée par e1, transmis au bloc intérieur et les variables de bloc sont attribuées des valeurs (en utilisant désambiguïsation).

key, *values = e1.next 
    #=> ["Actor", "Morgan", "33", ["A", "B"]] 
key 
    #=> "Actor" 
values 
    #=> ["Morgan", "33", ["A", "B"]] 

Le calcul du bloc interne est maintenant effectué.

b = keys[key].zip(values) 
    #=> keys["Actor"].zip(["Morgan", "33", ["A", "B"]]) 
    #=> [:name, :Age, :Films].zip(["Morgan", "33", ["A", "B"]]) 
    #=> [[:name, "Morgan"], [:Age, "33"], [:Films, ["A", "B"]]] 
b.to_h 
    #=> {:name=>"Morgan", :Age=>"33", :Films=>["A", "B"]} 

Maintenant, le deuxième et le dernier élément est généré par e1 et les mêmes calculs sont effectués.

key, *values = e1.next 
    #=> ["Actor", "Jack Black", "333", ["A", "A"]] 
b = keys[key].zip(values) 
    #=> [[:name, "Jack Black"], [:Age, "333"], [:Films, ["A", "A"]]] 
b.to_h 
    #=> {:name=>"Jack Black", :Age=>"333", :Films=>["A", "A"]} 

Lorsqu'une autre valeur est demandée à e1 on obtient ce qui suit.

e1.next 
    #=> StopIteration: iteration reached an end 

Cette exception est pris, ce qui e1 pour revenir au bloc externe. À ce stade e0 le génère ensuite (et dernière valeur).

a = e0.next 
    #=> [["Movie", "Titanic", "44", ["A", "A"]]] 

Les autres calculs sont similaires.