在ruby中将数组转换为哈希

时间:2017-10-09 10:11:01

标签: arrays json ruby hash

假设我有一个看起来像

的数组
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)

但是将数组项放入"电影"它会给我一个错误。和#34;演员"然后尝试创建像" Name"和"年龄"。

我如何按照自己的意愿制作?

6 个答案:

答案 0 :(得分:1)

请尝试以下代码,

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

请注意, Actor 不是散列的散列,它是哈希的数组,这是保持集合并将其转换为json的标准方法,如果你需要使用 to_json 方法。

答案 1 :(得分: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

这将产生

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

答案 2 :(得分:1)

您需要遍历数组并解析每个项目,并将其附加到生成的哈希值。

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

答案 3 :(得分:1)

r2中的值包含没有键的哈希值。你能做的最好的事情就是把它放到一个数组中。

这会奏效。可能会有一种更清洁的方式,但我现在还不确定:

: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

答案 4 :(得分:1)

我试着保留你写的例子。

首先,它必须针对数组(例如[a, b])而不是哈希({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"]}
    ]
}

答案 5 :(得分:0)

<强>代码

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

其余的计算方法类似。