我刚刚开始使用Ruby,我编写了一些代码来对CSV文件进行基本解析(Line是基本类,为简洁起见省略):
class File
def each_csv
each do |line|
yield line.split(",")
end
end
end
lines = Array.new
File.open("some.csv") do |file|
file.each_csv do |csv|
lines << Line.new(:field1 => csv[0], :field2 => csv[1])
end
end
我有一种感觉我会更好地以某种方式使用collect
,而不是将每个Line
推到数组上,但我无法理解如何做到这一点。
任何人都可以告诉我该怎么做,还是完全没问题呢?
编辑:我应该已经明确表示我实际上并不打算在生产中使用这段代码,而是更多地习惯语言的构造。知道有些库可以正确地执行此操作仍然很有用。
答案 0 :(得分:4)
这是一个(可能是疯狂的)想法,使用Struct类而不是滚动你自己的简单POD类。但是你想要的是拥有一个接受所有可以从文件数据生成的参数的构造函数。
Line = Struct.new(:field1, :field2, :field3)
然后在算法的核心,你需要像:
File.open("test.csv").lines.inject([]) do |result, line|
result << Line.new(line.split(",", Line.length))
end
或者更简洁,更具功能性:
lines = File.open("test.csv").lines.map { |line| Line.new(line.split(",", Line.length)) }
老实说,我没有多少使用过Struct类,但我应该这样做,并且我可能会重构已经编写好的东西来使用它。它允许您通过以下名称访问变量:
Line.field1 = blah
Line.field2 = 1
Ruby Struct类。
所以实际回答你的问题,并在上面看代码,我会说使用collect / map来执行计算要简单得多。 map函数和inject非常强大,我发现我经常使用它们。
答案 1 :(得分:2)
我不知道你是否知道它,但ruby有it's own class来解析和编写CSV文件。
我找到了一个使用collect将csv文件转换为哈希数组的示例。
def csv_to_array(file_location)
csv = CSV::parse(File.open(file_location, 'r') {|f| f.read })
fields = csv.shift
csv.collect { |record| Hash[*(0..(fields.length - 1)).collect {|index| [fields[index],record[index].to_s] }.flatten ] }
end
此示例取自this article。
如果您不熟悉*概念,它基本上会解散外部[]括号,将数组转换为逗号分隔的元素列表。
答案 2 :(得分:1)
你看过FasterCSV吗,它会做你在这里尝试做的事情,以及你在一些CSV文件中找到的一些脑死亡事件
答案 3 :(得分:0)
了解这对你有用(功能编程很有趣!):
尝试使用注入。 Inject将起始“累加器”作为参数,然后是两个参数块:
[1,2,3].inject(0) { |sum,num| sum+num }
自然是6
[1,2,3].inject(5) { |sum,num| sum+num }
是11
[1,2,3].inject(2) { |sum,num| sum*num }
是12
重点:
class Line
def initialize(options)
@options = options
end
def to_s
@options[:field1]+" "+@options[:field2]
end
end
File.open("test.csv").lines.inject([]) do |lines,line|
split = line.split(",")
lines << Line.new(:field1 => split[0],:field2 => split[1])
end