如何使用Ruby高效地从字符串中获取所需的格式化哈希?
当字符串以以下格式出现时,我希望以特定格式散列: 给定字符串:如何使用Ruby高效地从字符串中获取所需的格式化哈希?,ruby,string,hash,Ruby,String,Hash,当字符串以以下格式出现时,我希望以特定格式散列: 给定字符串: 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" =&
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
#转换成如下哈希(必需的哈希模式):
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
我尝试了很多方法,但这是最接近的:
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
为了解决方案的清晰性,我希望您能原谅我在叶子上留下了空哈希而不是空值
取消叶子:
def leaves_nil! hash
hash.each { |k,v| v.empty? ? hash[k] = nil : leaves_nil!(hash[k]) }
end
您也可以通过类似这样的方式获得输出
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
# }
# }
这是另一种需要较少数据来构建散列的方法。例如,如果
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}}
示例
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}}
请注意,与拆分(/'\n'/)不同,保留换行符。把他们留在这一点上是有意的;它们有一个重要的用途,如下所示
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({})>
enum
现在调用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 { |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"=>{}}}
b = line.split(/\s*=\s*/)
#=> ["A", "B", "C\n"]
b.reduce(h) { |g,w|
(w[-1] == '\n') ? g[w.chomp] = nil : g[w] ||= {} }
#=> {}
Array\each
传入块的第一个值是:
["A = B = C\n", {}]
将其分解或“消歧”为两个元素并分配给块变量:
line = "A = B = C\n"
h = {}
g = g["B"] #=> {}
w = "C\n"
我们现在执行块中的代码:
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 { |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"=>{}}}
b = line.split(/\s*=\s*/)
#=> ["A", "B", "C\n"]
b.reduce(h) { |g,w|
(w[-1] == '\n') ? g[w.chomp] = nil : g[w] ||= {} }
#=> {}
reduce
的初始值是我们正在构建的hashh
,它最初是空的。当h
和将“A”
传递到块中时
g = h #=> {}
w = "A"
所以(注意,“\n”
”需要双引号)
所以我们执行
g[w] ||= {}
#=> g['A'] ||= {}
#=> g['A'] = g['A'] || {}
#=> g['A'] = nil || {}
#=> {}
所以现在
h #=> {"A"=>{}}
然后将g[w]=>{}
传递回reduce
,传递给块的第二个元素的块变量为:
g = g["A"] #=> {}
w = "B"
自
我们再次执行
g[w] ||= {}
#=> g["B"] ||=> {} => {}
现在呢
h #=> {"A"=>{"B"=>{}}}
最后,[g[“B”],“C\n”]
被传递到块中,分解并分配给块变量:
line = "A = B = C\n"
h = {}
g = g["B"] #=> {}
w = "C\n"
但是在w
中出现换行符会导致
w[-1] == "\n" #=> true
告诉我们这是行中的最后一个字,因此我们需要去掉换行符并将值设置为nil
:
g[w.chomp] = nil
#=> g["C"] = nil
导致:
h #=> {"A"=>{"B"=>{"C"=>nil}}}
将换行符保留在字符串中提供了所需的“标志”,用于以不同于其他行的方式处理每行上的最后一个字
其他行的处理方式与此类似。谢谢您的回答。我将尝试获取null。您确定您的意思是
=curr[c.strip]=curr[c.strip]
?