Outputting single row from CSV file from specific header name - ruby

In ruby 3.1.2, using this CSV file:
make,model,color,doors,email
dodge,charger,black,4,practice1#whatever.com
ford,focus,blue,5,practice2#whatever.com
nissan,350z,black,2,practice3#whatever.com
mazda,miata,white,2,practice4#whatever.com
honda,civid,brown,4,practice5#whatever.com
corvette,stingray,red,2,practice6#whatever.com
ford,fiesta,blue,5,practice7#whatever.com
bmw,m4,black,2,practice8#whatever.com
audi,a5,blue,2,practice9#whatever.com
subaru,brz,black,2,practice10#whatever.com
lexus,rc,black,2,practice11#whatever.com
How would I be able to print out just one of the rows specific to the email. For example, the user enters: "practice11#whatever.com", and this is the output: lexus,rc,black,2,practice11#whatever.com

csv = CSV.read('filename.csv', headers: true)
row = csv.find {|row| row['email'] == 'practice11#whatever.com'}
=> #<CSV::Row "make":"lexus" "model":"rc" "color":"black" "doors":"2" "email":"practice11#whatever.com">
then map the output to a model if you want.

Related

Outputting data of a CSV using hash

When I have a csv file that looks like this:
make,model,color,doors,email
dodge,charger,black,4,practice1#whatever.com
ford,focus,blue,5,practice2#whatever.com
nissan,350z,black,2,practice3#whatever.com
mazda,miata,white,2,practice4#whatever.com
honda,civid,brown,4,practice5#whatever.com
corvette,stingray,red,2,practice6#whatever.com
ford,fiesta,blue,5,practice7#whatever.com
bmw,m4,black,2,practice8#whatever.com
audi,a5,blue,2,practice9#whatever.com
subaru,brz,black,2,practice10#whatever.com
lexus,rc,black,2,practice11#whatever.com
when I try to run my code I keep getting this error,
data [:model]
^^^^
I suppose this does not work like this but I was wondering if there is a way to make this work. I am just trying to let the program output all the different models. This is my code:
require "csv"
CSV.foreach("cars.csv", headers: true) do |row|
data = puts row.to_h
end
data [:model]
puts data
I get my csv file and then turn it into a hash and make it equal to data
Your data variable is not defined outside the loop and there is an additional space. To create a hash of hashes(lines).
One option could be to include the index using with_index and use it to fill the empty hash that you create before:
require "csv"
data = {}
CSV.foreach("cars.csv", headers: true).with_index do |row, i|
data[i] = row.to_h
end
pp data
Result:
{0=>
{"make"=>"dodge",
"model"=>"charger",
"color"=>"black",
"doors"=>"4",
"email"=>"practice1#whatever.com"},
... ,
... ,
... ,
10=>
{"make"=>"lexus",
"model"=>"rc",
"color"=>"black",
"doors"=>"2",
"email"=>"practice11#whatever.com"}}
Another option for grouping data is to read the CSV file into an array, see CSV.read in the docs to be able to group the data as requested.
On the array, you can do:
data.group_by { |d| d[:model] }

How to make user input to csv update the actual csv file

In ruby 3.1.2, I have this csv file:
make,model,color,doors,email
dodge,charger,black,4,practice1#whatever.com
ford,focus,blue,5,practice2#whatever.com
nissan,350z,black,2,practice3#whatever.com
mazda,miata,white,2,practice4#whatever.com
honda,civid,brown,4,practice5#whatever.com
corvette,stingray,red,2,practice6#whatever.com
ford,fiesta,blue,5,practice7#whatever.com
bmw,m4,black,2,practice8#whatever.com
audi,a5,blue,2,practice9#whatever.com
subaru,brz,black,2,practice10#whatever.com
lexus,rc,black,2,practice11#whatever.com
My current program allows a user to input an email and from that email it will go to that line and change the value of the model of a car, and then print out the csv onto the screen. What can be done to make the code also update the actual CSV file in the directory?
This is my code:
require "csv"
csv = CSV.read('cars.csv', headers: true)
print "Enter an email: \n> "
demo = gets.chomp
#print csv.find {|row| row['email'] == demo}
got = csv.find {|row| row['email'] == demo}
p got
p got.fields
p got['model']
got['model'] = 'rcf'
p got['model']
p got.fields
#prints out the csv file
puts csv.to_s
if my coding approach is different and if there's a better way don't hesitate to change any of my coding or completely not use it and go another path, please comment the code
Please refer below for your reference:
csv = CSV.read('cars.csv', headers: true)
print "Enter an email: \n> "
demo = gets.chomp
csv.map{|row| row['model'] = 'rcf' if row['email'] == demo}
puts csv.to_s
CSV.open("cars.csv", "wb") do |new_csv|
new_csv << %w[make model color doors email]
csv.each do |row|
new_csv << row
end
end
I hope this will help you.

How to generate a column in a CSV file instead of a row

So what I'm trying to do is read a specific column from an existing CSV file, parse some information out of the pulled data, then make a new CSV file with the newly parsed information in a single column. The header and first entry of the generated array go into the CSV file correctly, but after those, every other entry goes into the adjacent cells of the same row instead of creating a column, so it's like an L shape instead of just a line. Any ideas?
#!ruby.exe
require 'csv'
puts "Please enter a file name:" #user input file name (must be in same
folder as this file)
file = gets.chomp
begin
File.open(file, 'r')
rescue
print "Failed to open #{file}\n"
exit
end #makes sure that the file exists, if it does not it posts an error
data_file = File.new(file)
data = [] #initializes array for addresses from .csv
counter=0 #set counter up to allow for different sized files to be used
without issue
CSV.foreach(data_file, headers: true) do |row|
data << row.to_hash
counter+=1
end #goes through .csv one line ar a time
data.reject(&:empty?)
puts "Which column do you want to parse?"
column = gets.chomp
i=0
streets = []
while (i<counter)
address = data[i][column]
street_name = address.gsub(/^((\d[a-zA-Z])|[^a-zA-Z])*/, '')
streets.push(street_name)
i+=1
end
streets.reject(&:empty?)
puts "What do you want the output to be called?"
new_file = gets.chomp
CSV.open(new_file, "w", :write_headers=> true, :headers => [column]) do |hdr|
hdr << streets
end
You should scan the street array and insert it as a row, which means you need to place the line of data into an array before to send to the csv. Ok, maybe the code is simpler than the explanation:
CSV.open(new_file, "w", :write_headers=> true, :headers => [column]) do |csv_line|
streets.each { |street| csv_line << [street] }
end

Issue writing data to csv file in ruby

I have an issue writing to a CSV file in ruby and can't figure out.
> header = "Full Name, Email, Phone Number" csv_file =
> CSV.open("myfile.csv", "wb") do |csv|
> csv << header
> inactive_users_id.each do |inactive_id| #inactive_users_id is just an array on integers, which represent user id
> full_name = User.find(inactive_id).full_name
> email = User.find(inactive_id).email
> phone_num = User.find(inactive_id).phone_number
> desired_info = Array.new
> desired_info.push(full_name)
> desired_info.push(email)
> desired_info.push(phone_num)
> csv << desired_info
> end
> end
I do get following errors:
undefined method `map' for "Full Name, Email, Phone
Number":String
if I remove line csv << header my csv file is
literally like this: [138] --> which represents the id and other
things are not there.
What could be the issue?
Thank you!
While I cannot replicate your issues please try this instead:
headers = ["Full Name", "Email", "Phone Number"]
CSV.open("myfile.csv", "wb", write_headers: true, headers: headers ) do |csv|
User.where(id: inactive_users_id)
.pluck(:full_name, :email, :phone_number)
.each do |row|
csv << row
end
end
Here we are collecting all the Users in 1 query (rather than your current 3 per User) and just the needed columns are converted to an Array (using #pluck). Then we just push each one into the csv as a row
As pointed out in the comments in rails 3 pluck will not work with multiple columns (or at all depending on version) instead one should use select and then reference the attributes inside the loop to to create the row

How do I access the filename of the CSV file I just opened?

I have a method that looks like this:
def extract_websites
websites = []
csvs = Dir["#{#dir_name}/#{#state}/*.csv"]
csvs.each do |csv|
CSV.foreach(csv, headers: true) do |row|
websites << row['Website']
end
end
websites.uniq!
end
But what I need want to do is for each CSV file that is opened, I would like to detect the name of that file.
How do I do that?
In your sample the variable csv holds the path of the CSV file.
That local variable is available in the blocks of its children, it shares its scope down but not upwards.
So:
def extract_websites
websites = []
csvs = Dir["#{#dir_name}/#{#state}/*.csv"]
csvs.each do |csv|
puts File.expand_path(csv) # show the full path for each csv file
CSV.foreach(csv, headers: true) do |row|
puts csv # shows unexpanded path for each row of a csv
websites << row['Website']
end
end
websites.uniq!
end
should print out the path for each CSV file and for each row.

Resources