Convert CSV file into array of hashes

RubyCsvMultidimensional Array

Ruby Problem Overview


I have a csv file, some hockey stats, for example:

09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5

I want to save them in an array of hashes. I don't have any headers and I would like to add keys to each value like "time" => "09.09.2008" and so on. Each line should by accessible like arr[i], each value by for example arr[i]["time"]. I prefer CSV class rather than FasterCSV or split. Can you show the way or redirect to some thread where a similar problem was solved?

Ruby Solutions


Solution 1 - Ruby

Just pass headers: true

CSV.foreach(data_file, headers: true) do |row|
  puts row.inspect # hash
end

From there, you can manipulate the hash however you like.

(Tested with Ruby 2.0, but I think this has worked for quite a while.)

Edit

You say you don't have any headers - could you add a header line to the beginning of the file contents after reading them?

Solution 2 - Ruby

You can use the Ruby CSV parser to parse it, and then use Hash[ keys.zip(values) ] to make it a hash.

Example:

test = '''
09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5
'''.strip

keys = ['time', etc... ]
CSV.parse(test).map {|a| Hash[ keys.zip(a) ] }

Solution 3 - Ruby

This is a fantastic post by Josh Nichols which explains how to do what you're asking.

To summarize, here his code:

csv = CSV.new(body, :headers => true, :header_converters => :symbol, :converters => [:all, :blank_to_nil])
csv.to_a.map {|row| row.to_hash }
=> [{:year=>1997, :make=>"Ford", :model=>"E350", :description=>"ac, abs, moon", :price=>3000.0}, {:year=>1999, :make=>"Chevy", :model=>"Venture \"Extended Edition\"", :description=>nil, :price=>4900.0}, {:year=>1999, :make=>"Chevy", :model=>"Venture \"Extended Edition, Very Large\"", :description=>nil, :price=>5000.0}, {:year=>1996, :make=>"Jeep", :model=>"Grand Cherokee", :description=>"MUST SELL!\nair, moon roof, loaded", :price=>4799.0}]

So, you could save the body of your CSV file into a string called body.

body = "09.09.2008,1,HC Vitkovice Steel,BK Mlada Boleslav,1:0 (PP)
09.09.2008,1,HC Lasselsberger Plzen,RI OKNA ZLIN,6:2
09.09.2008,1,HC Litvinov,HC Sparta Praha,3:5"

And then run his code as listed above on it.

Solution 4 - Ruby

A little shorter solution

Parse string:

CSV.parse(content, headers: :first_row).map(&:to_h)

Parse file:

CSV.open(filename, headers: :first_row).map(&:to_h)

Solution 5 - Ruby

Slight variation on Nathan Long's answer

data_file = './sheet.csv'
data = []
CSV.foreach(data_file, headers: true) do |row|
  data << row.to_hash
end

Now data is an array of hashes to do your bidding with!

Solution 6 - Ruby

The headers option to the CSV module accepts an array of strings to be used as the headers, when they're not present as the first row in the CSV content.

CSV.parse(content, headers: %w(time number team_1 team_2 score))

This will generate an enumerable of hashes using the given headers as keys.

Solution 7 - Ruby

You can try the following gem also

require 'csv_hasher'
arr_of_hashes = CSVHasher.hashify('/path/to/csv/file')

The keys of the returned hashes will be the header values of the csv file.

If you want to pass your own keys then

keys = [:key1, :key2, ... ]
arr_of_hashers = CSVHasher.hashify('/path/to/csv/file', { keys: keys }) 

Solution 8 - Ruby

I guess this is the shortest version:

keys = ["time", ...]
CSV.parse(content, headers: keys).map(&:to_h)

Solution 9 - Ruby

you could also use the SmarterCSV gem, which returns data from CSV files as Ruby hashes by default.

It has a lot of features, including processing the data in chunks, which is very benefitial for huge data files.

  require 'smarter_csv'

  options = {} # see GitHub README
  data = SmarterCSV.process(your_file_name, options)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMythagoView Question on Stackoverflow
Solution 1 - RubyNathan LongView Answer on Stackoverflow
Solution 2 - RubyAJcodezView Answer on Stackoverflow
Solution 3 - RubyCodeBikerView Answer on Stackoverflow
Solution 4 - RubyPavel EvstigneevView Answer on Stackoverflow
Solution 5 - RubylacostenycoderView Answer on Stackoverflow
Solution 6 - RubyWill MaddenView Answer on Stackoverflow
Solution 7 - Rubygaurav.singharoyView Answer on Stackoverflow
Solution 8 - RubySofiSunView Answer on Stackoverflow
Solution 9 - RubyTiloView Answer on Stackoverflow