0

If using the 'csv' library in ruby, how would you replace the headers without re-reading in a file?

foo.csv

'date','foo',bar'
1,2,3
4,5,6

Using a CSV::Table because of this answer

Here is a working solution, however it requires writing and reading from a file twice.

require 'csv'
@csv = CSV.table('foo.csv')

# Perform additional operations, like remove specific pieces of information. 

# Save fixed csv to a file (with incorrect headers)
File.open('bar.csv','w') do |f|
  f.write(@csv.to_csv)
end

# New headers
new_keywords = ['dur','hur', 'whur']

# Reopen the file, replace the headers, and print it out for debugging
# Not sure how to replace the headers of a CSV::Table object, however I *can* replace the headers of an array of arrays (hence the file.open)
lines = File.readlines('bar.csv')
lines.shift
lines.unshift(new_keywords.join(',') + "\n")
puts lines.join('')

# TODO: re-save file to disk

How could I modify the headers without reading from disk twice?

'dur','hur','whur'
1,x,3
4,5,x

Update
For those curious, here is the unabridged code. In order to use things like delete_if() the CSV must be imported with the CSV.table() function.

Perhaps the headers could be changed by converting the csv table into an array of arrays, however I'm not sure how to do that.

Community
  • 1
  • 1
spuder
  • 17,437
  • 19
  • 87
  • 153
  • 1
    In your example you're reading one csv, writing to another, reading the second another time and eventually printing it all as a string. Do you want the exact same content just with different headers? Is the desired output the last snippet? – Anthony Nov 05 '14 at 02:51
  • I've added some code comments that should clarify this better. I'm trying to replace "date","foo","bar" with "dur","hur","whur" in a less clunky manor. – spuder Nov 05 '14 at 02:58
  • 1
    why not in the initial read of the file, skip the headers with `headers: true` and just write what you want the headers to be in the new csv? – Anthony Nov 05 '14 at 03:17
  • I am doing some operations on the csv table that require knowing what the headers are. – spuder Nov 05 '14 at 04:07

1 Answers1

1

Given a test.csv file whose contents look like this:

id,name,age
1,jack,8
2,jill,9

You can replace the header row using this:

require 'csv'

array_of_arrays = CSV.read('test.csv')

p array_of_arrays # => [["id", "name", "age"],
                  # =>  ["1", "jack", "26"],
                  # =>  ["2", "jill", "27"]]    

new_keywords = ['dur','hur','whur']

array_of_arrays[0] = new_keywords

p array_of_arrays # => [["dur", "hur", "whur"],
                  # =>  ["1", " jack", " 26"],
                  # =>  ["2", " jill", " 27"]]

Or if you'd rather preserve your original two-dimensional array:

new_array = Array.new(array_of_arrays)
new_array[0] = new_keywords

p new_array # => [["dur", "hur", "whur"],
            # =>  ["1", " jack", " 26"],
            # =>  ["2", " jill", " 27"]]

p array_of_arrays # => [["id", "name", "age"],
                  # =>  ["1", "jack", "26"],
                  # =>  ["2", "jill", "27"]]
Travis Hohl
  • 2,176
  • 2
  • 14
  • 15
  • 1
    Thanks, however the code is already using CSV.table() so that the headers are created a symbols, thus allowing the use of delete_if(). Can this be done with CSV.table() https://github.com/spuder/simple-ynab/blob/eddf9871a30daaab0938b08f882ff7a789f6db56/tests/doublearray.rb – spuder Nov 09 '14 at 22:01