如何从枚举器中删除链式延迟/延迟可枚举方法?

时间:2018-01-03 13:53:45

标签: ruby-on-rails ruby

我有一个带有CSV和行号的枚举器:

require "csv"

csv = CSV.parse("a,b,c\nd,e,f\nx,x,x", headers: true)
csv_with_line_numbers = csv.to_enum.with_index

puts csv_with_line_numbers.inspect
=> #<Enumerator: #<Enumerator: #<CSV::Table mode:col_or_row row_count:3>:each>:with_index>

我想从with_index删除链式csv_with_line_numbers,所以我最终得到:

puts csv_with_line_numbers.inspect
=> #<Enumerator: #<CSV::Table mode:col_or_row row_count:3>:each>

我可以通过枚举并将其置于更好的状态来实现这一目标,例如

csv_with_line_numbers.to_a.map(&:first)

但实际上CSV是huuuuuge所以这可能效率不高!

要解决这个问题,我想删除尚未执行的lazy链式方法,或者找到另一个解决方案:

  • 具有内存效率(例如,对于大型CSV枚举器)
  • 使用惯用的Ruby
  • 假设再次构建枚举器是不切实际的(例如,我不再能够访问源csv变量)

1 个答案:

答案 0 :(得分:1)

对我来说这感觉就像一个XY问题 - 你为什么不这样做:

  • 保持index原样 - 它没有造成多大伤害?或者,
  • 存储enum 而不索引,只在必要时添加?添加索引比添加 - 然后删除它更加惯用。

话虽如此,我不知道从枚举器中“取消链接”方法的任何方法。但是,您可以通过以下方法删除索引而不将其转换为数组:

csv_with_line_numbers.map { |row, index| row }

或者:

csv_with_line_numbers.map { |*row_with_index| row_with_index.first }

另一方面,你在这里讨论“延迟评估”,但是你的代码没有懒惰地评估CSV !! CSV.parse会将整个文件加载到内存中,所以对于一个“huuuuuge”[sic]文件你无论如何都会有记忆问题。

标准方法是使用CSV.foreach代替CSV.parse;从而一次只将一行加载到存储器中。对于更高级的应用程序(例如“仅读取行300,000 - 310,000”),您可以考虑使用File.open并构建lazy enumerator来跳过解析文件的第一个/最后一个块。