我有一个带有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
变量)答案 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来跳过解析文件的第一个/最后一个块。