在这种情况下使用收集会更好吗?

时间:2009-01-08 09:27:12

标签: ruby

我刚刚开始使用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推到数组上,但我无法理解如何做到这一点。

任何人都可以告诉我该怎么做,还是完全没问题呢?

编辑:我应该已经明确表示我实际上并不打算在生产中使用这段代码,而是更多地习惯语言的构造。知道有些库可以正确地执行此操作仍然很有用。

4 个答案:

答案 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