2014-11-21 7 views
7

मैं एक विशेष प्रारूप में हैश करना चाहते हैं जब एक स्ट्रिंग नीचे प्रारूप में प्रकट होता है:रूबी के साथ एक कुशल तरीके से एक स्ट्रिंग से वांछित स्वरूपित हैश कैसे प्राप्त करें?

को देखते हुए स्ट्रिंग:

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

उत्तर के लिए धन्यवाद। मैं बदले में नल पाने की कोशिश करूंगा। –

+0

पत्तियों को कम करने के लिए अद्यतन देखें। – mudasobwa

+0

धन्यवाद @ mudasobwa –

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

धन्यवाद - @ योगेश –

+0

क्या आप वाकई '= curr [c.strip] = curr [c.strip] '? –

+0

हाँ @theTinMan, मुझे यकीन है। –

1

यह एक और तरीका है कि कम डेटा की आवश्यकता है हैश बनाने के लिए।

A = B 
A = B = C 

और लाइनों के आदेश है महत्वहीन: अगर, उदाहरण के लिए, लाइन

A = B = C = D 

मौजूद है, वहाँ निम्नलिखित में से किसी के लिए कोई जरूरत नहीं है।

कोड

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

नोटिस String#lines, split(/'\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({})> 

हम एक सरणी के लिए प्रगणक परिवर्तित तत्वों 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 अब invokes 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", {}] 

जो विघटित या है "disambiguated" में दो तत्व है और ब्लॉक चर करने के लिए आवंटित:

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[-1] == "\n" #=> true 

में में w परिणाम न्यू लाइन चरित्र की उपस्थिति हमें बता यह है लाइन में आखिरी शब्द, इसलिए हमें न्यूलाइन चरित्र को बंद करने और nil:

g[w.chomp] = nil 
    #=> g["C"] = nil 
पर मान सेट करने की आवश्यकता है

में जिसके परिणामस्वरूप:

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

स्ट्रिंग में न्यू लाइन चरित्र छोड़कर दूसरों की तुलना में अलग तरह से प्रत्येक पंक्ति पर अंतिम शब्द प्रसंस्करण के लिए आवश्यक "झंडा" प्रदान की है।

अन्य लाइनों को समान रूप से संसाधित किया जाता है।

संबंधित मुद्दे