[英]Converting an array to hash in ruby
Supposed I have an array that looks like 假设我有一个看起来像的数组
testarr = [["Actor", "Morgan", "33", ["A","B"]],
["Movie", "Titanic", "44", ["A","A"]],
["Actor", "Jack Black", "333", ["A","A"]]]
I want to convert this into a hash which will be converted into a json eventually. 我想将其转换为哈希,最终将转换为json。
I want it to look like 我希望它看起来像
{
"Actor" => {
{ "name" : "Morgan",
"Age" : 33",
"Films: { "A", "B" }} ,
{ "name" : "Jack Black",
"Age" : 44",
"Films: { "A", "A" }}
}
"Movie" => {
{ "Title" : "Titanic"
"Gross" : "44"
"Actors" : { "A", "A" }
}
}
Not sure about the exact format, but whatever makes sense. 不知道确切的格式,但是任何有意义的。
I tried 我试过了
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)
But it gives me an error for putting the array item into "Movie" and "Actor" then trying to create keys like "Name" and "Age". 但这给我一个错误,将数组项放入“电影”和“演员”,然后尝试创建诸如“名称”和“年龄”之类的键。
How can I make this as I desire? 我怎样才能做到这一点?
Please try the below code, 请尝试以下代码,
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
And the o/p is like below, 而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"]}]}
Please note here the Actor is not hash of hashes, it's array of hashes, this is the standard way of keeping collection and convert it to json if you need by using to_json method. 请注意, Actor不是哈希的哈希,而是哈希的数组,这是保留集合并将其转换为json(如果需要的话,使用to_json方法)的标准方法。
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
this will produce 这将产生
{"Actor"=>[{"name"=>"Morgan", "age"=>"33", "films"=>["A", "B"]}, {"name"=>"Jack Black", "age"=>"333", "films"=>["A", "A"]}], "Movie"=>[{"name"=>"Titanic", "age"=>"44", "films"=>["A", "A"]}]}
You need to iterate through the array and parse each item, appending it to the resultant hash. 您需要遍历数组并解析每个项目,并将其添加到生成的哈希中。
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
This will produce: 这将产生:
{"Actor"=>[{:name=>"Morgan", :age=>"33", :movies=>["A", "B"]}, {:name=>"Jack Black", :age=>"333", :movies=>["A", "A"]}], "Movie"=>[{:title=>"Titanic", :gross=>"44", :actors=>["A", "A"]}]}
The value in your :actor
contains a hash without a key. :actor
中的值包含没有键的哈希。 The best thing you can do is put that into an array. 您可以做的最好的事情就是将其放入数组中。
This will work. 这将起作用。 There might be a cleaner way, but I'm not sure how at the 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
Output: 输出:
{"Actor"=>[{:name=>"Morgan", :age=>"33", :films=>["A", "B"]}, {:name=>"Jack Black", :age=>"333", :films=>["A", "A"]}], "Movie"=>[{:title=>"Titanic", :gross=>"44", :actors=>["A", "A"]}]}
I tried to keep the example you wrote. 我试图保留您编写的示例。
First of all, it must be shaped for Array(such as [a, b]
) not Hash( {a, b}
) list of items 首先,它必须针对Array(例如
[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"]
}
]
}
and then your function should be like this ... 然后你的功能应该是这样的...
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
Then it's time to test! 然后该测试了! as your codes,
作为您的代码,
testarr = [
["Actor", "Morgan", "33", ["dsfds","dsfdsf"]],
["Movie", "Titanic", "44", ["dsfds","dfdsf"]],
["Actor", "Jack Black", "333", ["ssdsfds","dsfdsf"]]
]
puts hashing(testarr)
It will return this: 它将返回此:
{
"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"]}
]
}
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
Example (using testarr
defined in the question) 示例(使用
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"]}
# ]
# }
Explanation 说明
See Enumerable#group_by , Hash#transform_values , Array#zip and Array#to_h . 请参见Enumerable#group_by , Hash#transform_values , Array#zip和Array#to_h 。
The steps are as follows. 步骤如下。
h = testarr.group_by(&:first)
#=> { "Actor"=>[
# ["Actor", "Morgan", "33", ["A", "B"]],
# ["Actor", "Jack Black", "333", ["A", "A"]]
# ],
# "Movie"=>[
# ["Movie", "Titanic", "44", ["A", "A"]]
# ]
# }
Though not quite equivalent, you can think of testarr.group_by(&:first)
as being "shorthand" for testarr.group_by { |a| a.first }
尽管不尽相同,但是您可以将
testarr.group_by(&:first)
视为testarr.group_by { |a| a.first }
“简写”。 testarr.group_by { |a| a.first }
. testarr.group_by { |a| a.first }
。 Continuing, 继续,
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>
The first element is generated by the enumerator e0
, passed to the block and the block variable is set equal to that value. 第一个元素由枚举器
e0
生成,传递给该块,并且将块变量设置为等于该值。
a = e0.next
#=> [["Actor", "Morgan", "33", ["A", "B"]],
# ["Actor", "Jack Black", "333", ["A", "A"]]]
A second enumerator is now created. 现在创建了第二个枚举器。
e1 = a.map
#=> #<Enumerator: [["Actor", "Morgan", "33", ["A", "B"]],
# ["Actor", "Jack Black", "333", ["A", "A"]]]:map>
The first value is generated by e1
, passed to the inner block and the block variables are assigned values (using disambiguation ). 第一个值由
e1
生成,传递给内部块,并为块变量分配值(使用歧义 )。
key, *values = e1.next
#=> ["Actor", "Morgan", "33", ["A", "B"]]
key
#=> "Actor"
values
#=> ["Morgan", "33", ["A", "B"]]
The inner block calculation is now performed. 现在执行内部块计算。
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"]}
Now the second and last element is generated by e1
and the same calculations are performed. 现在,第二个和最后一个元素由
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"]}
When another value is sought from e1
we obtain the following. 当从
e1
寻求另一个值时,我们得到以下结果。
e1.next
#=> StopIteration: iteration reached an end
This exception is caught, causing e1
to return to the outer block. 捕获此异常,导致
e1
返回到外部块。 At this point e0
generates it next (and last value). 此时,
e0
生成下一个(也是最后一个值)。
a = e0.next
#=> [["Movie", "Titanic", "44", ["A", "A"]]]
The remaining calculations are similar. 其余计算类似。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.