1

I know how to do it with CSV.read, but CSV.open and enumerator I'm not sure how. Or how do I omit those specific row before loading them in the new_csv[] ?

Thanks!

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    

Code Example

2 Answers 2

1

If you want to skip the first four rows plus the header, this are some options.

Get pure array:

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

or keep the csv object

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

or using 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
Sign up to request clarification or add additional context in comments.

Comments

0

Let's begin by creating a CSV file:

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

We can use CSV::foreach without a block to return an enumerator.

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

The enumerator csv generates CSV::ROW objects:

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

Before continuing let me Enumerator#rewind csv so that csv.next will once again generate its first element.

csv.rewind

Suppose we wish to skip the first two records. We can do that using Enumerator#next:

2.times { csv.next }

Now continue generating elements with the enumerator, mapping them to an array of hashes:

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

See Kernel#loop and CSV::Row#to_h. The enumerator csv raises a StopInteration exception when next invoked after the enumerator has generated its last element. As you see from its doc, loop handles that exception by breaking out of the loop.

loop is a very versatile method. I generally use it in place of while and until, as well as when I need it to handle a StopIteration exception.


If you just want the values, then:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.