简体   繁体   English

将数组转换为Ruby中的哈希

[英]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_byHash#transform_valuesArray#zipArray#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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM