2014-11-21 41 views
7

我想在一個特定的格式哈希當一個字符串出現在以下格式:如何使用Ruby以有效的方式從字符串中獲取所需的格式化哈希?

給定的字符串:

str = 'A 
A = B 
A = B = C 
A = B = D 
A = E = F 
G = H 
G = I 
G = J' 

#進入這樣的(需要散列模式)的哈希:

{ 
    "A" => { 
    "B" => { 
     "C" => nil, 
     "D" => nil 
    }, 
    "E" => { 
     "F" => nil 
    }, 
    }, 
    "G" => { 
    "H" => nil, 
    "I" => nil, 
    "J" => nil 
    } 
} 

我嘗試過很多辦法,但是這是最接近:

output = Hash.new 
line_hash = Hash.new 
str.each_line do |line| 
    arr = line.split("=") 
    e = arr.first.strip 
    line_hash[e] = {} 
    arr.each_with_index do |ele, i| 
    break unless arr[i+1] 
    line_hash[ele.strip] = arr[i+1] unless output.keys.include?(ele.strip) 
    end 
    output[e] = line_hash unless output.keys.include?(e) 
end 

回答

9
str = "A\nA = B\nA = B = C\nA = B = D\nA = E = F\nG = H\nG = I\nG = J" 

curr = h = {} 

str.each_line { |l| 
    l.chomp.split(/\s*=\s*/m).each { |c| 
    curr = curr[c] ||= {}; 
    } 
    curr = h 
} 

puts h 
# => { 
# "A" => { 
# "B" => { 
#  "C" => {}, 
#  "D" => {} 
# }, 
# "E" => { 
#  "F" => {} 
# } 
# }, 
# "G" => { 
# "H" => {}, 
# "I" => {}, 
# "J" => {} 
# } 
# } 

我希望你能原諒我的葉子只剩下空空的哈希值,而不是空值溶液的澄清度的緣故。

以抵消葉:

def leaves_nil! hash 
    hash.each { |k,v| v.empty? ? hash[k] = nil : leaves_nil!(hash[k]) } 
end 
+0

感謝您的回答。我會嘗試取而代之。 – 2014-11-21 14:11:59

+0

查看如何取消樹葉的更新。 – mudasobwa 2014-11-21 14:36:06

+0

謝謝@mudasobwa – 2014-11-21 14:44:17

2

您還可以得到輸出通過這樣的

str = 'A 
A = B 
A = B = C 
A = B = D 
A = E = F 
G = H 
G = I 
G = J' 

curr = h = {} 
lines = str.split("\n").map{|t| t.split(/\s*=\s*/m) } 
lines.each do |line| 
    line.each { |c| curr = curr[c.strip] = curr[c.strip] || ((line.last == c) ? nil : {}); } 
    curr = h 
end 

輸出

#=> { 
#  "A" => { 
#   "B" => { 
#    "C" => nil, 
#    "D" => nil 
#   }, "E" => { 
#    "F" => nil 
#   } 
#  }, "G" => { 
#   "H" => nil, 
#   "I" => nil, 
#   "J" => nil 
#  } 
# } 
+1

謝謝 - @Yogesh – 2014-11-21 14:43:51

+0

你確定你的意思是'= curr [cstrip] = curr [c.strip]'? – 2014-11-21 17:13:09

+0

是@theTinMan,我相信。 – 2014-11-22 09:28:12

1

這是一個需要較少的數據的另一種方式構建哈希。如果,例如,線

A = B = C = D 

存在時,就沒有必要爲以下任一操作:

A = B 
A = B = C 

和行的順序是不重要的。

代碼

def hashify(str) 
    str.lines.each_with_object({}) { |line, h| 
    line.split(/\s*=\s*/).reduce(h) { |g,w| 
     (w[-1] == "\n") ? g[w.chomp] = nil : g[w] ||= {} } } 
end 

str =<<_ 
A = B = C 
G = I 
A = B = D 
A = E = F 
G = H 
A = K 
G = J 
_ 

hashify(str) 
    #=> {"A"=>{"B"=>{"C"=>nil, "D"=>nil}, "E"=>{"F"=>nil}, "K"=>nil}, 
    # "G"=>{"I"=>nil, "H"=>nil, "J"=>nil}} 

說明

對於str以上:

a = str.lines 
    #=> ["A = B = C\n", "A = B = D\n", "A = E = F\n", 
    # "G = H\n", "G = I\n", "G = J\n"] 

請注意,與split(/'\n'/)不同,String#lines保留換行符。保持這一點是有意的;它們有一個重要的目的,如下所示。

enum = a.each_with_object({}) 
    #=> #<Enumerator: ["A = B = C\n", "A = B = D\n", "A = E = F\n", "G = H\n", 
    #     "G = I\n", "G = J\n"]:each_with_object({})> 

我們可以枚舉轉換爲數組看到Array#each將傳遞到塊中的元素:

enum.to_a 
    #=> [["A = B = C\n", {}], ["A = B = D\n", {}], ["A = E = F\n", {}], 
    # ["G = H\n", {}], ["G = I\n", {}], ["G = J\n", {}]] 

enum現在調用each給每個元件通入塊:

enum.each { |line, h| line.split(/\s*=\s*/).reduce(h) { |g,w| 
      (w[-1] == '\n') ? g[w.chomp] = nil : g[w] ||= {} } } 
    #=> {"A"=>{"B"=>{"C\n"=>{}, "D\n"=>{}}, "E"=>{"F\n"=>{}}}, 
    # "G"=>{"H\n"=>{}, "I\n"=>{}, "J\n"=>{}}} 

Array#each傳入該塊的第一個值是:

["A = B = C\n", {}] 

其被分解或「消歧」到它的兩個元件和分配給該塊的變量:

b = line.split(/\s*=\s*/) 
    #=> ["A", "B", "C\n"] 
b.reduce(h) { |g,w| 
    (w[-1] == '\n') ? g[w.chomp] = nil : g[w] ||= {} } 
    #=> {} 

初始值:

line = "A = B = C\n" 
h = {} 

我們現在在塊執行代碼對於reduce是我們正在構建的散列h,它最初是空的。當h"A"被傳遞到塊,

g = h #=> {} 
w = "A" 

左右(提的是,需要爲"\n"雙引號)

w[-1] == "\n" 
    #=> "A" == '\n' 
    #=> false 

所以我們執行

g[w] ||= {} 
    #=> g['A'] ||= {} 
    #=> g['A'] = g['A'] || {} 
    #=> g['A'] = nil || {} 
    #=> {} 

所以現在

h #=> {"A"=>{}} 

g[w] => {}然後被傳遞迴回reduce和用於傳遞到塊中的第二元件的塊的變量是:

g = g["A"] #=> {} 
w = "B" 

由於

w[-1] == "\n" #=> false 

我們再次執行

g[w] ||= {} 
#=> g["B"] ||=> {} => {} 

和現在

h #=> {"A"=>{"B"=>{}}} 

最後,[g["B"], "C\n"]傳遞到塊,分解,分配給塊變量:

g = g["B"] #=> {} 
w = "C\n" 

但換行符的存在w結果

w[-1] == "\n" #=> true 

告訴我們它是因此我們需要去掉換行符並將其值設置爲nil

g[w.chomp] = nil 
    #=> g["C"] = nil 

導致:

h #=> {"A"=>{"B"=>{"C"=>nil}}} 

字符串中離開換行符處理每行的最後一個字不同於其他人提供所需的「標誌」。

其他行的處理方式相似。

相關問題