i cant code
i cant code

Reputation: 343

Rails CSV remove column that have empty header

I am receiving a csv file that has some blank headers but data exists in these columns. I want to remove the blank header and it's associated column in rails.

Sample csv

#report
,Code,Price,Orders,,Mark,
1,X91,4.55,4,xxx,F,23

What I'd like returned:

Code,Price,Orders,Mark
A91,4.55,4,F

This is what I have so far as there is also comments on the csv which i am ignoring.

CSV.open("output.csv", "w") do |output_csv|
          CSV.foreach("out.csv", encoding: "bom|utf-8", skip_lines: /^#/, headers: true).with_index(0) do |row, i|
            output_csv << row.headers if i == 0
            output_csv << row
          end
        end

Upvotes: 0

Views: 1146

Answers (2)

3limin4t0r
3limin4t0r

Reputation: 21130

Although I largely agree with the answer of arieljuod, there are a few things that might go wrong. row.header_row? will always return false, since the return_headers: true option isn't set, thus leaving out the header. delete_if is a mutating method, so there is no need to save the result in a variable. This only returns itself so you can chain it with other methods.

The following would be enough:

read_options = {
  encoding: "bom|utf-8",
  skip_lines: /^#/,
  headers: true,
  return_headers: true,
}

CSV.open("output.csv", "w") do |output_csv|
  CSV.foreach("out.csv", read_options) do |row|
    row.delete_if { |header, _field| header.blank? }
    output_csv << row
  end
end

Note that blank? is a Ruby on Rails method, but since you've tagged the question with this should be fine.

From the CSV::new documentation (also describing CSV::foreach) options:

:return_headers

When false, header rows are silently swallowed. If set to true, header rows are returned in a CSV::Row object with identical headers and fields (save that the fields do not go through the converters).

Upvotes: 2

arieljuod
arieljuod

Reputation: 15838

You can use CSV::Row's delete_if method https://ruby-doc.org/stdlib-2.4.1/libdoc/csv/rdoc/CSV/Row.html#method-i-delete_if, something like:

CSV.open("output.csv", "w") do |output_csv|
  CSV.foreach("out.csv", encoding: "bom|utf-8", skip_lines: /^#/, headers: true) do |row|
    clean_row = row.delete_if { |header, _field| header.blank? }
    output_csv << clean_row.headers if row.header_row?
    output_csv << clean_row
  end
end

Upvotes: 3

Related Questions