转换阵列,红宝石

问题描述:

散列认为我有一个数组,看起来像转换阵列,红宝石

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

我想这个转换成散列它最终会被转换成JSON。

我希望它看起来像

{ 

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

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

不能确定确切的格式,但不管是有道理的。

我试图

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) 

但它给了我一个错误的把数组项为“电影”和“演员”,然后想创建“名称”和“年龄”键。

我该如何做到这一点?

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 

这将产生

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

谢谢。我怎样才能真正把演员的年龄和电影作品放在名字键里? Like Name => Morgan => {Age:33,Filmo = [...] – user6792790

请尝试下面的代码,

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 

和O/p是像下面,

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

请注意这里的演员不是哈希散列,它的哈希值的数组,这是保持收集并将其转换为json的标准方法,如果需要,可以使用to_json方法。

+0

谢谢!但是我得到一个未定义的方法'礼物?' for nil:NilClass(NoMethodError)。这是一个有效的方法吗? – user6792790

+0

是的,它是标准的方法。您是否在使用Rails? – Mohanraj

+0

我正在使用普通红宝石 – user6792790

您需要通过数组迭代和分析每一个项目,其附加到结果哈希。

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 

这将产生:

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

值在:actor包含哈希没有钥匙。你可以做的最好的事情是把它放到一个数组中。

这将工作。有可能是一个更清洁的方式,但我不知道此刻如何:

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 

输出:

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

谢谢。我怎样才能真正把演员的年龄和电影作品放在名字键里? Like Name => Morgan => {年龄:33,Filmo = [...]} – user6792790

我试图让你写的例子。

首先,它必须为形阵列(如[a, b])不HASH({a, b})项目

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

,然后你的函数应该是这样的列表...

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 

然后是时候测试了! 为您的代码,

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

puts hashing(testarr) 

它会返回此:

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

谢谢。我怎样才能真正把演员的年龄和电影作品放在名字键里? Like Name => Morgan => {Age:33,Filmo = [...]} – user6792790

+0

简单!再一次包裹你的结构。在你的表达式中,Name => Morgan => {...}'与包装类似'Name => {Morgan => {...}}'。所有结构中的键都必须具有完整的结构以实现像我所包装的那样的价值。顺便说一句,我建议原来的一个,而不是新的更清楚地保护和定义的对象。 –

代码

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

例(使用问题定义testarr

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

说明

Enumerable#group_byHash#transform_valuesArray#zipArray#to_h

步骤如下。

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

虽然不是很等价的,你能想到的testarr.group_by(&:first)为“速记”为testarr.group_by { |a| a.first }。接着,

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> 

由枚举e0产生的第一元件,传递到块和块变量被设定为等于该值。

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

现在创建第二个枚举器。

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

的第一个值是由e1产生,传递到内块和块变量(使用消歧)分配的值。

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

现在执行内部块计算。

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

现在,第二个也是最后一个元素由e1生成,并执行相同的计算。

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

当另一值从e1寻求我们得到以下几点。

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

该异常被捕获,导致e1返回到外部块。此时e0产生它(和最后一个值)。

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

其余的计算是类似的。