2017-10-09 239 views
1

散列認爲我有一個數組,看起來像轉換陣列,紅寶石

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) 

但它給了我一個錯誤的把數組項爲「電影」和「演員」,然後想創建「名稱」和「年齡」鍵。

我該如何做到這一點?

回答

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

謝謝。我怎樣才能真正把演員的年齡和電影作品放在名字鍵裏? Like Name => Morgan => {Age:33,Filmo = [...] – user6792790

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

請注意這裏的演員不是哈希散列,它的哈希值的數組,這是保持收集並將其轉換爲json的標準方法,如果需要,可以使用to_json方法。

+0

謝謝!但是我得到一個未定義的方法'禮物?' for nil:NilClass(NoMethodError)。這是一個有效的方法嗎? – user6792790

+0

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

+0

我正在使用普通紅寶石 – user6792790

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

值在: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

1

我試圖讓你寫的例子。

首先,它必須爲形陣列(如[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 => {...}}'。所有結構中的鍵都必須具有完整的結構以實現像我所包裝的那樣的價值。順便說一句,我建議原來的一個,而不是新的更清楚地保護和定義的對象。 –

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

其餘的計算是類似的。