Question: Not able to place csv data in a Hash

Question

Not able to place csv data in a Hash

Answers 3
Added at 2016-12-27 13:12
Tags
Question

I have a CSV file with two columns:

PPS_Id Amount
123    100
1234   150

I read data from this file and insert in a array using the code below:

CSV.foreach("filename.CSV", headers: true) do |row|
  file_details << row.inspect # hash
end

I am then trying to push the data in the file_details into a hash with PPS_Id as key and Amount as Value, I am using the code below:

file_details_hash = Hash.new

file_details.each { |x|  
  file_details_hash[x['PPS_Id']] = x['Amount']
}

But when I print the result I get nothing just {"PPS_Id"=>"Amount"}

Can you please help

Answers
nr: #1 dodano: 2016-12-27 13:12

First of all, you are collecting strings into an array (see String#inspect):

file_details << row.inspect

After that you call (sic!) String#[] on that strings:

x['PPS_Id'] #⇒ "PPS_Id", because string contains this substring

That said, your code has nothing but errors. You might achieve what you want with:

csv = CSV.parse(File.read("filename.CSV"), col_sep: "\s")
csv[1..-1].to_h
#⇒ {
#    "123" => "100",
#   "1234" => "150"
# }
nr: #2 dodano: 2016-12-27 13:12

Using inspect will save your CSV rows as strings, so obviously you won't be able get what you need. Instead try this:

file_details = CSV.read("filename.csv")

Read CSV directly will create an 2D array that you can then iterate over, which will look like this: [["PPS_Id", "Amount"], ["123", "100"], ["1234", "150"]]

From there you can slightly modify your approach:

file_details.each do |key, value|
  file_details_hash[key] = value
end

To receive a hash like this: {"PPS_Id"=>"Amount", "123"=>"100", "1234"=>"150"}

nr: #3 dodano: 2016-12-27 15:12

Your code, modified to work

You need to specify the column separator for your csv, and remove inspect.

require 'csv'

file_details = []
CSV.foreach("filename.CSV", headers: true, col_sep: "\s" ) do |row|
  file_details << row
end

file_details_hash = Hash.new
file_details.each { |x|
  file_details_hash[x['PPS_Id']] = x['Amount']
}

p file_details_hash
#=> {"123"=>"100", "1234"=>"150"}

It now returns what you expected to get.

Shorter solution

Read the csv, drop the first line (header) and convert to a Hash :

p CSV.read("filename.CSV", col_sep: "\s").drop(1).to_h
#=> {"123"=>"100", "1234"=>"150"}
Source Show
◀ Wstecz