2013-10-05 89 views
5

分組創建新的哈希說我有一個哈希看起來像這樣在Ruby中:通過公共密鑰值在Ruby中

{ :ie0 => "Hi", :ex0 => "Hey",  :eg0 => "Howdy", 
    :ie1 => "Hello", :ex1 => "Greetings", :eg1 => "Good day"} 

是什麼把它轉換成類似一個好辦法:

{ "0" => 
    { 
     "ie" => "Hi", "ex" => "Hey", "eg" => "Howdy" 
    }, 
    "1" => 
    { 
     "ie" => "Hello", "ex" => "Greetings", "eg" => "Good day" 
    } 
} 
+3

對於初學者,請嘗試:a.group_by {| e | e [0] [/ \ d /]} – Mason

+0

好的提示,謝謝。 – tvalent2

回答

3

你問了辦法做到這一點,所以答案是:一種方式,你或你的同事能夠理解,從現在維持六個月。

首先,你需要一個Hash with autovivification,因爲你正在創建一個嵌套的散列結構。這是一個非常有用的編碼模式,這將簡化您的應用程序代碼:

# Copied & pasted from the question 
old_hash = { :ie0 => "Hi", :ex0 => "Hey", :eg0 => "Howdy", :ie1 => "Hello", :ex1 => "Greetings", :eg1 => "Good day"} 

# Auto-vivify 
new_hash = Hash.new { |h, k| h[k] = { } } 

然後,您可以循環通過現有的密鑰在這個簡單的風格,打破了每個鍵的部分,並用它們來保存該值在新的哈希:

old_hash.each_pair do |key, value| 
    key =~ /^(..)(.)$/    # Make a regex group for each string to parse 
    new_hash[$2][$1] = value   # The regex groups become the new hash keys 
end 

puts new_hash 

我得到這樣的輸出:

{"0"=>{"ie"=>"Hi", "ex"=>"Hey", "eg"=>"Howdy"}, "1"=>{"ie"=>"Hello", "ex"=>"Greetings", "eg"=>"Good day"}} 
+0

是的,我得到了同樣的東西。雖然不知道自動生動化! – tvalent2

+0

適用於我,Ruby 2.0.0。我將編輯以添加完整的代碼。 – Dogweather

+0

啊,只是沒有把'new_hash'。太棒了,謝謝你! – tvalent2

3

這不是很漂亮,但這個工程:

input = { :ie0 => "Hi", :ex0 => "Hey",  :eg0 => "Howdy", 
      :ie1 => "Hello", :ex1 => "Greetings", :eg1 => "Good day"} 

output = input.inject({}) do |result, item| 
    item[0] =~ /(?<key>[^\d]+)(?<index>\d+)/ 
    key, index = $1, $2 
    value = item[1] 

    result[index] ||= {} 
    result[index].merge! { key => value } 
    result 
end 

puts output 
+0

我不得不做'result [index] .merge!(key => value)',但它有效。哇謝謝! – tvalent2

1

編輯:跟我道歉的upvoter,我現在寧願dislke這個答案(但沒有這麼多,我會自己冷靜下來)。我會讓它留在這裏,因爲它的歷史意義(當然還有10點)。在它的許多缺點中,它只允許結果中的一位數字密鑰。我提交了另一個更好的解決方案。

h = {ie0: "Hi", ex0: "Hey", eg0: "Howdy", ie1: "Hello", ex1: "Greetings", eg1: "Good day"} 

n = h.keys.map {|k| k.to_s[0..-2]}.uniq.size # => 3 

Hash[*h.to_a.each_slice(n).to_a.map {|s| [s.first.first.to_s[-1], Hash[*s.map {|v| [v.first.to_s[0..-2], v.last]}.flatten]]}.flatten] 
+0

很好,謝謝。 – tvalent2

2
require 'awesome_print' 

hsh = { 
      :ie0 => "Hi", 
      :ex0 => "Hey", 
      :eg0 => "Howdy", 
      :ie1 => "Hello", 
      :ex1 => "Greetings", 
      :eg1 => "Good day" 
     } 

new_hsh = hsh.each_with_object(Hash.new { |h, k| h[k] = { } }) do |(k,v),h| 
     h[k[-1]].merge!({k[0..-2] => v}) 
end 
ap new_hsh 

輸出(帶awesome_print格式)

{ 
    "0" => { 
     "ie" => "Hi", 
     "ex" => "Hey", 
     "eg" => "Howdy" 
    }, 
    "1" => { 
     "ie" => "Hello", 
     "ex" => "Greetings", 
     "eg" => "Good day" 
    } 
} 
+0

不錯,奧雅納! (評論已經結束,但它不夠長..) –

+0

@CarySwoveland非常感謝! :) –

0

這是一個使用@梅森的建議的方法(在關於這個問題的評論)使用group_by

h = {ie0: "Hi", ex0: "Hey", eg0: "Howdy", ie999: "Hello", ex999: "Greetings", eg999: "Good day"} 

編輯:新的和改進的(?):

p Hash[h.group_by {|e| e[0][/\d+/]}.map {|k,v| [k, Hash[v.map {|a| [a.first.to_s[/[^\d]+/], a.last]}]]}] 

以前我有:

hh = h.group_by { |e| e[0][/\d+/] } 
hh.each_key {|k| hh[k] = Hash[*[hh[k].map {|v| [v.first.to_s[/[^\d]+/], v.last]}].flatten]} 

建議,歡迎。我發現這是一個有趣的問題,並且喜歡閱讀其他答案,我發現這些答案是多樣的和創新的。

+0

不知道each_key。尼斯。 – Dogweather