Ruby — удаление строк в csv-файле с помощью enumerator CSV.open

#ruby #csv

#ruby #csv

Вопрос:

Я знаю, как это сделать с помощью CSV.read, но CSV.open и enumerator я не уверен, как это сделать. Или как мне опустить эти конкретные строки перед их загрузкой в new_csv[] ?

Спасибо!

 new_csv = []
CSV.open(file, headers:true) do |unit|
     units = unit.each
     units.select do |row|
     #delete row [0][1][2][3]
     new_csv << row
end    
 

Пример кода

Ответ №1:

Если вы хотите пропустить первые четыре строки плюс заголовок, вот несколько вариантов.

Получить чистый массив:

 new_csv = CSV.read(filename)[5..]
 

или сохранить объект csv

 new_csv = []
CSV.open(filename, headers:true) do |csv|
  csv.each_with_index do |row, i|
    new_csv << row if i > 3
  end
end
 

или с помощью Enumerable#each_with_object:

 csv = CSV.open(filename, headers:true)
new_csv = csv.each_with_index.with_object([]) do |(row, i), ary|
  ary << row if i > 3
end
 

Ответ №2:

Начнем с создания CSV-файла:

 contents =<<~END
name,nickname,age
Robert,Bobbie,23
Wilma,Stretch,45
William,Billy-Bob,72
Henrietta,Mama,53
END
  
FName = 'x.csv'

File.write(FName, contents)
  #=> 91
 

Мы можем использовать CSV::foreach без блока для возврата перечислителя.

 csv = CSV.foreach(FName, headers:true)
  #=> #<Enumerator: CSV:foreach("x.csv", "r", headers: true)>
 

Enumerator csv генерирует объекты CSV::ROW:

 obj = csv.next
  #=> #<CSV::Row "name":"Robert" "nickname":"Bobbie" "age":"23">
obj.class
  #=> CSV::Row
 

Прежде чем продолжить, позвольте мне Enumerator#rewind csv , чтобы csv.next он снова сгенерировал свой первый элемент.

 csv.rewind
 

Предположим, мы хотим пропустить первые две записи. Мы можем сделать это с помощью Enumerator#next:

 2.times { csv.next }
 

Теперь продолжайте генерировать элементы с помощью enumerator, сопоставляя их с массивом хэшей:

 loop.map { csv.next.to_h }
  #=> [{"name"=>"William", "nickname"=>"Billy-Bob", "age"=>"72"},
  #    {"name"=>"Henrietta", "nickname"=>"Mama", "age"=>"53"}]   
 

См. Kernel#loop и CSV::Row#to_h . При вызове enumerator csv возникает StopInteration исключение next после того, как enumerator сгенерировал свой последний элемент. Как вы видите из его документа, loop обрабатывает это исключение, выходя из цикла.

loop это очень универсальный метод. Обычно я использую его вместо while and until , а также когда мне это нужно для обработки StopIteration исключения.


Если вам просто нужны значения, то:

 csv.rewind
2.times { csv.next }
loop.with_object([]) { |_,arr| arr << csv.next.map(amp;:last) }
  #=> [["William", "Billy-Bob", "72"],
  #    ["Henrietta", "Mama", "53"]]