Galet
Galet

Reputation: 6299

How to add new column in CSV string in rails

I want to add new column and update existing values in CSV response. How can I do simpler and better way of doing the below transformations?

Input

id,name,country
1,John,US
2,Jack,UK
3,Sam,UK

I am using following method to parse the csv string and add new column

# Parse original CSV
rows = CSV.parse(csv_string, headers: true).collect do |row|
  hash = row.to_hash
  # Merge additional data as a hash.
  hash.merge('email' => '[email protected]')
end

# Extract column names from first row of data
column_names = rows.first.keys
# Generate CSV after transformation of csv
csv_response = CSV.generate do |csv|
  csv << column_names
  rows.each do |row|
    # Extract values for row of data
    csv << row.values_at(*column_names)
  end
end

I am using following method to parse the csv and update existing values

name_hash = {"John" => "Johnny", "Jack" => "Jackie"}

Parse original CSV

rows = CSV.parse(csv_string, headers: true).collect do |row|
  hash = row.to_hash
  hash['name'] = name_hash[hash['name']] if name_hash[hash['name']] != nil
  hash
end

# Extract column names from first row of data
column_names = rows.first.keys
# Generate CSV after transformation of csv
csv_response = CSV.generate do |csv|
  csv << column_names
  rows.each do |row|
    # Extract values for row of data
    csv << row.values_at(*column_names)
  end
end

Upvotes: 1

Views: 502

Answers (1)

iGian
iGian

Reputation: 11193

One possible option given the following reference data to be used for modifying the table:

name_hash = {"John" => "Johnny", "Jack" => "Jackie"}
sample_email = {'email' => '[email protected]'}

Just store in rows the table converted to hash:

rows = CSV.parse(csv_string, headers: true).map(&:to_h)
#=> [{"id"=>"1", "name"=>"John", "country"=>"US"}, {"id"=>"2", "name"=>"Jack", "country"=>"UK"}, {"id"=>"3", "name"=>"Sam", "country"=>"UK"}]


Then modify the hash based on reference data (I used Object#then for Ruby 2.6.1 alias of Object#yield_self for Ruby 2.5):

rows.each { |h| h.merge!(sample_email).then {|h| h['name'] = name_hash[h['name']] if name_hash[h['name']] } }
#=> [{"id"=>"1", "name"=>"Johnny", "country"=>"US", "email"=>"[email protected]"}, {"id"=>"2", "name"=>"Jackie", "country"=>"UK", "email"=>"[email protected]"}, {"id"=>"3", "name"=>"Sam", "country"=>"UK", "email"=>"[email protected]"}]


Finally restore the table:

csv_response = CSV.generate(headers: rows.first.keys) { |csv| rows.map(&:values).each { |v| csv << v } }

So you now have:

puts csv_response

# id,name,country,email
# 1,Johnny,US,[email protected]
# 2,Jackie,UK,[email protected]
# 3,Sam,UK,[email protected]

Upvotes: 1

Related Questions