如何使用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
的初始值是我们正在构建的hash
h
,它最初是空的。当
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]