我认为我已经从字符串创建了多个数组,但如果我尝试检查数组,则会收到错误。
File.open("livestock.txt", "r") do |file|
file.readlines.each do |x|
if x.match(/:*:/)
# puts x.inspect
# strip string
x.gsub!(/[^A-Za-z]/, '')
x.downcase!
puts x.inspect
x = Array.new(){Hash.new}
# puts x.inspect
pigs.inspect
else
# puts "no"
end
end
end
animals.rb:12:in `block (2 levels) in <main>': undefined local variable or method `pigs' for main:Object (NameError)
from animals.rb:2:in `each'
from animals.rb:2:in `block in <main>'
from animals.rb:1:in `open'
from animals.rb:1:in `<main>'
理想情况下我想创建pig = [] 然后将哈希添加到此数组,例如:
pigs = [{"name"=>"peggy", "id"=>1, "owner"=>"wolcott farms"},
{"name"=>"sue", "id"=>2, "owner"=>"blue moon farms"},
{"name"=>"eddie", "id"=>3, "owner"=>"sunrise farms"}
]
和奶牛等相同
我的文本文件animals.txt是
::pigs::
name, id, owner
peggy, 1, wolcott farms
sue, 2, blue moon farms
eddie, 3, sunrise farms
::cows::
name, id, owner
dee, 3, black hat farms
sunny, 2, blue moon farms
bess, 4, wolcott farms
答案 0 :(得分:0)
由于Ruby v1.8,因此无法创建局部变量。实例变量,是(使用Object#instance_variable_set),局部变量,编号
@CodeGnome提供了一种使用给定名称创建实例变量的方法。我不认为实例变量的集合是适当的数据结构。我建议你考虑使用哈希代替。你可以这样做。
<强>代码强>
def doit(fname)
File.read(fname).
split(/\n{2,}/). # split paragraphs
each_with_object({}) do |s,h|
outer_key, inner_key_names, *inner_values = s.split(/\n/)
inner_keys = inner_key_names.split(/,\s+/)
h[outer_key[/(?<=::)[^:]+/]] =
inner_values.each_with_object([]) { |values_str, a|
a << inner_keys.zip(values_str.split(/,\s+/)).to_h }
end
end
示例强>
首先让我们创建你的文件。
FName = "animals.txt"
data =<<_
::pigs::
name, id, owner
peggy, 1, wolcott farms
sue, 2, blue moon farms
eddie, 3, sunrise farms
::cows::
name, id, owner
dee, 3, black hat farms
sunny, 2, blue moon farms
bess, 4, wolcott farms
_
File.write(FName, data)
#=> 203
现在在此文件上执行方法。
doit(FName)
#=> {"pigs"=>[{"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "},
# {"name"=>"sue", "id"=>"2", "owner"=>"blue moon farms"},
# {"name"=>"eddie", "id"=>"3", "owner"=>"sunrise farms"}],
# "cows"=>[{"name"=>"dee", "id"=>"3", "owner "=>"black hat farms "},
# {"name"=>"sunny", "id"=>"2", "owner "=>"blue moon farms "},
# {"name"=>"bess", "id"=>"4", "owner "=>"wolcott farms"}]}
<强>解释强>
步骤如下。
b = File.read(FName).split(/\n{2,}/)
#=> ["::pigs:: \nname, id, owner\npeggy, 1, wolcott farms \nsue, 2, blue moon farms\neddie, 3, sunrise farms",
# "::cows:: \nname, id, owner \ndee, 3, black hat farms \nsunny, 2, blue moon farms \nbess, 4, wolcott farms\n"]
接下来我们有
enum = b.each_with_object({})
#=> #<Enumerator: ["::pigs:: \nname, id, owner\npeggy, 1, wolcott farms \nsue, 2, blue moon farms\neddie, 3, sunrise farms",
# "::cows:: \nname, id, owner \ndee, 3, black hat farms \nsunny, 2, blue moon farms \nbess, 4, wolcott farms\n"]:each_with_object({})>
我们可以将enum
转换为数组,以查看它将生成的值并传递给它的块:
enum.to_a
#=> [["::pigs:: \nname, id, owner\npeggy, 1, wolcott farms \nsue, 2, blue moon farms\neddie, 3, sunrise farms", {}],
# ["::cows:: \nname, id, owner \ndee, 3, black hat farms \nsunny, 2, blue moon farms \nbess, 4, wolcott farms\n", {}]] The empty arrays above will be populated as the calculations proceed.
我们现在将enum
的第一个元素传递给块并分配块变量
s,h = enum.next
#=> ["::pigs:: \nname, id, owner\npeggy, 1, wolcott farms \nsue, 2, blue moon farms\neddie, 3, sunrise farms", {}]
s #=> "::pigs:: \nname, id, owner\npeggy, 1, wolcott farms \nsue, 2, blue moon farms\neddie, 3, sunrise farms"
h => {}
空格式h
的值将被块修改,如下所示。
现在,对s
和h
的这些值执行块计算。
outer_key, inner_key_names, *inner_values = s.split(/\n/)
#=> ["::pigs:: ",
# "name, id, owner",
# "peggy, 1, wolcott farms ",
# "sue, 2, blue moon farms", "eddie, 3, sunrise farms"]
outer_key
#=> "::pigs:: "
inner_key_names
#=> "name, id, owner"
inner_values
#=> ["peggy, 1, wolcott farms ",
# "sue, 2, blue moon farms",
# "eddie, 3, sunrise farms"]
inner_keys = inner_key_names.split(/,\s+/)
#=> ["name", "id", "owner"]
h[outer_key[/(?<=::)[^:]+/]] =
inner_values.each_with_object([]) { |values_str, a|
a << inner_keys.zip(values_str.split(/,\s+/)).to_h }
# => [{"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "},
# {"name"=>"sue", "id"=>"2", "owner"=>"blue moon farms"},
# {"name"=>"eddie", "id"=>"3", "owner"=>"sunrise farms"}]
h #=> {"pigs"=>[{"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "},
# {"name"=>"sue", "id"=>"2", "owner"=>"blue moon farms"},
# {"name"=>"eddie", "id"=>"3", "owner"=>"sunrise farms"}]}
让我们更仔细地研究这最后的计算。
outer_key[/(?<=::)[^:]+/]
#=> "pigs"
enum1 = inner_values.each_with_object([])
#=> #<Enumerator: ["peggy, 1, wolcott farms ", "sue, 2, blue moon farms",
# "eddie, 3, sunrise farms"]:each_with_object([])>
enum1.to_a
#=> [["peggy, 1, wolcott farms ", []],
# ["sue, 2, blue moon farms", []],
# ["eddie, 3, sunrise farms", []]]
enum1
生成的第一个元素被传递给块,块变量被分配。
values_str, a = enum1.next
#=> ["peggy, 1, wolcott farms ", []]
values_str
#=> "peggy, 1, wolcott farms "
a #=> []
现在执行块计算。
b = inner_keys.zip(values_str.split(/,\s+/))
#=> ["name", "id", "owner"].zip(["peggy", "1", "wolcott farms "])
#=> [["name", "peggy"], ["id", "1"], ["owner", "wolcott farms "]]
c = b.to_h
#=> {"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "}
a << c
#=> [{"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "}]
enum1
生成的其余两个元素的处理方式相似,结果为
h #=> {"pigs"=>[{"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "},
# {"name"=>"sue", "id"=>"2", "owner"=>"blue moon farms"},
# {"name"=>"eddie", "id"=>"3", "owner"=>"sunrise farms"}]
剩下的计算(针对奶牛)是相似的。
@pigs和@cows
如果你坚持使用那些实例变量,很容易从上面构造的哈希生成它们。
h = {"pigs"=>[{"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "},
{"name"=>"sue", "id"=>"2", "owner"=>"blue moon farms"},
{"name"=>"eddie", "id"=>"3", "owner"=>"sunrise farms"}],
"cows"=>[{"name"=>"dee", "id"=>"3", "owner "=>"black hat farms "},
{"name"=>"sunny", "id"=>"2", "owner "=>"blue moon farms "},
{"name"=>"bess", "id"=>"4", "owner "=>"wolcott farms"}]}
h.each { |k,v| instance_variable_set("@#{k}", v) }
我们现在有:
@pigs
#=> [{"name"=>"peggy", "id"=>"1", "owner"=>"wolcott farms "},
# {"name"=>"sue", "id"=>"2", "owner"=>"blue moon farms"},
# {"name"=>"eddie", "id"=>"3", "owner"=>"sunrise farms"}]
@cows
#=> [{"name"=>"dee", "id"=>"3", "owner "=>"black hat farms "},
# {"name"=>"sunny", "id"=>"2", "owner "=>"blue moon farms "},
# {"name"=>"bess", "id"=>"4", "owner "=>"wolcott farms"}]
答案 1 :(得分:0)
您无法使用局部变量,但您可以使用Object#instance_variable_get和Object#instance_variable_set来执行此类元编程。例如:
str = File.read '/tmp/livestock.txt'
records = str.split /\n\n+/
records.map! { |r| r.split /\n/ }
records.map do |r|
var = ?@ << r.shift.strip.delete(?:)
fields = r.shift.strip.scan /[^,]+/
hashes = r.map { |e| e.split(?,).flat_map &:strip }.
map { |e| fields.zip e }.
map &:to_h
instance_variable_set var,
instance_variable_get(var).to_a.push(hashes).flatten!
end;
# The data is now stored correctly in the following instance variables.
@pigs
@cows
请注意,如果因为您在REPL中进行测试而 @pigs 或 @cows 已经存在,那么您的结果可能与您的预期不符。确保调用Object#remove_instance_variable,将变量设置为nil,或者在测试之间创建类的新实例。