Cleanest ruby code to split a string with specific rules
imagine an array like this
[
"A definition 1: this is the definition text",
"A definition 2: this is some other definition text",
"B definition 3: this could be: the definition text"
]
I want to end up with the following hash
hash = {
:A => ["A definition 1", "this 开发者_开发知识库is the definition text", "A definition 2", "this is some other definition text"],
:B => ["B definition 3", "this could be: the definition text"]
}
I'm creating a glossary, with a hash of each letter of the alphabet with definition arrays.
I'm pretty new to Ruby so what I have looks really inelegant and I'm struggling on the split regex of the line on the colon so that the 3rd line only splits on the first occurrence.
Thanks!
Edit Here's what I have so far
def self.build(lines)
alphabet = Hash.new()
lines.each do |line|
strings = line.split(/:/)
letter = strings[0][0,1].upcase
alphabet[letter] = Array.new if alphabet[letter].nil?
alphabet[letter] << strings[0]
alphabet[letter] << strings[1..(strings.size-1)].join.strip
end
alphabet
end
Provided raw_definitions is your input:
sorted_defs = Hash.new{|hash, key| hash[key] = Array.new;}
raw_definitions.each do |d|
d.match(/^([a-zA-Z])(.*?):(.*)$/)
sorted_defs[$1.upcase]<<$1+$2
sorted_defs[$1.upcase]<<$3.strip
end
Just for fun, here's a purely-functional alternative:
defs = [
"A definition 1: this is the definition text",
"A definition 2: this is some other definition text",
"B definition 3: this could be: the definition text"
]
hash = Hash[
defs.group_by{ |s| s[0].to_sym }.map do |sym,strs|
[ sym, strs.map{ |s| s[2..-1].split(/\s*:\s*/,2) }.flatten ]
end
]
require 'pp'
pp hash
#=> {:A=>
#=> ["definition 1",
#=> "this is the definition text",
#=> "definition 2",
#=> "this is some other definition text"],
#=> :B=>["definition 3", "this could be: the definition text"]}
And a not-purely-functional variation with the same results:
hash = defs.group_by{ |s| s[0].to_sym }.tap do |h|
h.each do |sym,strs|
h[sym] = strs.map{ |s| s[2..-1].split(/\s*:\s*/,2) }.flatten
end
end
Note that these solutions only work in Ruby 1.9 due to the use of s[0].to_sym
; to work in 1.8.7 you would have to change this to s[0,1].to_sym
. To make the first solution work in 1.8.6 you would further have to replace Hash[ xxx ]
with Hash[ *xxx.flatten ]
精彩评论