#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"]]