转换阵列,红宝石
散列认为我有一个数组,看起来像转换阵列,红宝石
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"]}]}
请尝试下面的代码,
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方法。
谢谢!但是我得到一个未定义的方法'礼物?' for nil:NilClass(NoMethodError)。这是一个有效的方法吗? – user6792790
是的,它是标准的方法。您是否在使用Rails? – Mohanraj
我正在使用普通红宝石 – 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"]}]}
谢谢。我怎样才能真正把演员的年龄和电影作品放在名字键里? 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"]}
]
}
谢谢。我怎样才能真正把演员的年龄和电影作品放在名字键里? Like Name => Morgan => {Age:33,Filmo = [...]} – user6792790
简单!再一次包裹你的结构。在你的表达式中,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_by,Hash#transform_values,Array#zip和Array#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"]]]
其余的计算是类似的。
谢谢。我怎样才能真正把演员的年龄和电影作品放在名字键里? Like Name => Morgan => {Age:33,Filmo = [...] – user6792790