I'm working on the JumpStart Labs Event Manager, specifically the time/day of the week targeting, and I'm running into trouble. When I run the following code through Terminal, it gives me the following error [EDIT]:
austin-winslows-macbook-4:event_manager HypnoBoy$ ruby event_manager.rb
event_manager.rb:8: odd number list for Hash
...vent_attendees.csv', {headers: true, header_converters: :sym...
^
event_manager.rb:8: syntax error, unexpected ':', expecting '}'
...vent_attendees.csv', {headers: true, header_converters: :sym...
^
event_manager.rb:8: Can't assign to true
...ttendees.csv', {headers: true, header_converters: :symbol})
^
event_manager.rb:8: syntax error, unexpected ':', expecting '='
...ders: true, header_converters: :symbol})
I've posted my code below, and am looking for suggestions! Something about the syntax is obviously off, but I've followed the steps to the letter thus far, and haven't had any problems, so I'm not sure where to look anymore. Any help would be a great help, thanks!
require 'csv'
require 'sunlight/congress'
require 'erb'
require 'date'
Sunglight::Congress.api_key = "e179a6973728c4dd3fb1204283aaccb5"
contents = CSV.open('event_attendees.csv', {headers: true, header_converters: :symbol})
def clean_zipcode(zipcode)
zipcode.to_s.rjust(5,"0")[0..4]
end
def clean_phone(number)
number.to_s.rjust(10,"0")[0..4]
end
def legislators_by_zipcode(zipcode)
Sunglight::Congress::Legislator.by_zipcode(zipcode)
end
def peak_days
time = row[:regdate]
day_array = []
time.each { |t|
array << Datetime.strptime(t, '%m/%d/%Y %H:%M').wday }
end
def peak_hours
time = row[:regdate]
hr_array = []
time.each { |t|
array << DateTime.strptime(t, '%m/%d/%Y %H:%M').hour }
array
end
def save_thanks_you_letters(id,form_letter)
Dir.mkdir("output") unless Dir.exists? "output"
filename = "output/thanks_#{id}.html"
File.open(filename, 'w') { |file|
file.puts form_letter}
end
puts "EventManager Initialized!"
template_letter = File.read "form_letter.erb"
erb_template = ERB.new template_letter
contents.each { |row|
id = row[0]
name = row[:first_name]
zipcode = clean_zipcode(row[:zipcode])
phone = clean_phone(row[:homephone])
legislators = legislators_by_zipcode(zipcode)
form_letter = erb_template.result(binding)
save_thank_you_letters(id,form_letter)
}
from the doc CSV::open you are using the construct :
open( filename, options = Hash.new )
So you line :
contents = CSV.open 'event_attendees.csv', headers: true, header_converters: :symbol is wrong,as from 2nd parameter onward it is expecting a Hash. Thus change it to:
contents = CSV.open('event_attendees.csv', {headers: true, header_converters: :symbol})
I completed this exercise today. I didn't have to change the contents = CSV.open line. What caused the error for me was that the date was not formatted in the Excel file. I formatted that date column to mm/dd/yyyy hh:mm in Excel. Also capitalization seemed to matter in the '%m/%d/%Y %H:%M' string -- I used lowercase 'y'.
This is what my first time exercise looks like:
# Iteration: Time Targeting
contents = CSV.open "event_attendees.csv", headers: true, header_converters: :symbol
regtimes = Array.new(25, 0)
contents.each do |row|
reghour = DateTime.strptime(row[:regdate],'%m/%d/%y %H:%M').hour
regtimes[reghour] += 1
end
Related
I have a CSV file. in csv some fields are blank. i want to update these fields with some value. I have try following but no luck.
CSV.foreach("/home/mypc/Desktop/data.csv", { encoding: "UTF-8", headers: true, header_converters: :symbol, converters: :all}).with_index do |row,i|
if row[:images].nil?
row[:images] << ['im1']
end
end
row[:images] ||= "im1"
will set the images cell of your row to "im1" if it's empty.
If you want to write a new CSV file with updated cells, you could use :
require 'csv'
write_parameters = { write_headers: true, headers: %w(images name) }
read_parameters = { encoding: 'UTF-8',
headers: true,
header_converters: :symbol,
converters: :all }
CSV.open('new_data.csv', 'w+', write_parameters) do |new_csv|
CSV.foreach('data.csv', read_parameters) do |row|
row[:images] ||= 'im1'
new_csv << row
end
end
With data.csv :
images,name
im2,name2
im3,name3
,name1
im4,name4
im5,
new_data.csv becomes :
images,name
im2,name2
im3,name3
im1,name1
im4,name4
im5,
If you're sure that new_data.csv is properly written, you could delete data.csv and rename new_data.csv to data.csv.
I wouldn't write data.csv in place. If anything goes wrong, you'd lose data.
I'm trying to read from .CSV file and create objects with attributes of every row.
My code works fine:
def self.load_csv
puts "Name of a file?"
filename = STDIN.gets.chomp
rows = []
text = File.read(filename).gsub(/\\"/,'""')
CSV.parse(text, headers: true, header_converters: :symbol) do |row|
row = row.to_h
row = row.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
rows << row
end
rows.map do |row|
Call.new(row)
end
end
end
Now I wanted to take filename from STDIN. I simply changed:
def self.load_csv(filename)
rows = []
text = File.read(filename).gsub(/\\"/,'""')
CSV.parse(text, headers: true, header_converters: :symbol) do |row|
row = row.to_h
row = row.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
rows << row
end
rows.map do |row|
Call.new(row)
end
end
end
and when I try ruby program.rb filename.csv I got error no implicit conversion of String into IO, and after removing line with File.read it does nothing - like an infinite loop maybe? Of course I invoke ceratain methods with STDIN argument in different parts of the code. I used similiar code for reading from STDIN with success in the past, what am I doing wrong this time?
This code is working:
require 'csv'
class Call
def initialize(args)
end
end
def load_csv(filename)
rows = []
text = File.read(filename).gsub(/\\"/,'""')
CSV.parse(text, headers: true, header_converters: :symbol) do |row|
row = row.to_h
row = row.each_with_object({}){ |(k,v), h| h[k.to_sym] = v }
rows << row
end
rows.map { |row| Call.new(row) }
end
filename = ARGV[0]
load_csv(filename)
I've searched and haven't found a method for this particular conundrum. I have two CSV files of data that sometimes relate to the same thing. Here's an example:
CSV1 (500 lines):
date,reference,amount,type
10/13/2015,,1510.40,sale
10/13/2015,,312.90,sale
10/14/2015,,928.50,sale
10/15/2015,,820.25,sale
10/12/2015,,702.70,credit
CSV2 (20000 lines):
reference,date,amount
243534985,10/13/2015,312.90
345893745,10/15/2015,820.25
086234523,10/14/2015,928.50
458235832,10/13/2015,1510.40
My goal is to match the date and amount from CSV2 with the date and amount in CSV1, and write the reference from CSV2 to the reference column in the corresponding row.
This is a simplified view, as CSV2 actually contains many many more columns - these are just the relevant ones, so ideally I'd like to refer to them by header name or maybe index somehow?
Here's what I've attempted, but I'm a bit stuck.
require 'csv'
data1 = {}
data2 = {}
CSV.foreach("data1.csv", :headers => true, :header_converters => :symbol, :converters => :all) do |row|
data1[row.fields[0]] = Hash[row.headers[1..-1].zip(row.fields[1..-1])]
end
CSV.foreach("data2.csv", :headers => true, :header_converters => :symbol, :converters => :all) do |row|
data2[row.fields[0]] = Hash[row.headers[1..-1].zip(row.fields[1..-1])]
end
data1.each do |data1_row|
data2.each do |data2_row|
if (data1_row['comparitive'] == data2_row['comparitive'])
puts data1_row['identifier'] + data2_row['column_thats_important_and_wanted']
end
end
end
Result:
22:in `[]': no implicit conversion of String into Integer (TypeError)
I've also tried:
CSV.foreach('data2.csv') do |data2|
CSV.foreach('data1.csv') do |data1|
if (data1[3] == data2[4])
data1[1] << data2[1]
puts "Change made!"
else
puts "nothing changed."
end
end
end
This however did not match anything inside the if statement, so perhaps not the right approach?
The headers method should help you match columns--from there it's a matter of parsing and writing the modified data back out to a file.
Solved.
data1 = CSV.read('data1.csv')
data2 = CSV.read('data2.csv')
data2.each do |data2|
data1.each do |data1|
if (data1[5] == data2[4])
data1[1] = data2[1]
puts "Change made!"
puts data1
end
end
end
File.open('referenced.csv','w'){ |f| f << data1.map(&:to_csv).join("")}
The Old.csv file contains these headers, "article_category_id", "articleID", "timestamp", "udid", but some of the values in those columns are strings. So, I am trying to convert them to integers and store in another CSV file, New.csv. This is my code:
require 'csv'
require 'time'
CSV.foreach('New.csv', "wb", :write_headers=> true, :headers =>["article_category_id", "articleID", "timestamp", "udid"]) do |csv|
CSV.open('Old.csv', :headers=>true) do |row|
csv['article_category_id']=row['article_category_id'].to_i
csv['articleID']=row['articleID'].to_i
csv['timestamp'] = row['timestamp'].to_time.to_i unless row['timestamp'].nil?
unless udids.include?(row['udid'])
udids << row['udid']
end
csv['udid'] = udids.index(row['udid']) + 1
csv<<row
end
end
But, I am getting the following error: in 'foreach': ruby wrong number of arguments (3 for 1..2) (ArgumentError).
When I change the foreach to open, I get the following error: undefined method '[]' for #<CSV:0x36e0298> (NoMethodError). Why is that? And how can I resolve it? Thanks.
CSV#foreach does not accept file access rights as second parameter:
CSV.open('New.csv', :headers=>true) do |csv|
CSV.foreach('Old.csv',
:write_headers => true,
:headers => ["article_category_id", "articleID", "timestamp", "udid"]
) do |row|
row['article_category_id'] = row['article_category_id'].to_i
...
csv << row
end
end
CSV#open should be placed before foreach. You are to iterate the old one and produce the new one. Inside the loop you should change row and than append it to the output.
You can refer my code:
require 'csv'
require 'time'
CSV.open('New.csv', "wb") do |csv|
csv << ["article_category_id", "articleID", "timestamp", "udid"]
CSV.foreach('Old.csv', :headers=>true) do |row|
array = []
article_category_id=row['article_category_id'].to_i
articleID=row['articleID'].to_i
timestamp = row['timestamp'].to_i unless row['timestamp'].nil?
unless udids.include?(row['udid'])
udids << row['udid']
end
udid = udids.index(row['udid']) + 1
array << [article_category_id, articleID, timestamp, udid]
csv<<array
end
end
The problem with Vinh answer is that at the end array variable is an array which has array inside.
So what is inserted indo CVS looks like
[[article_category_id, articleID, timestamp, udid]]
And that is why you get results in double quotes.
Please try something like this:
require 'csv'
require 'time'
CSV.open('New.csv', "wb") do |csv|
csv << ["article_category_id", "articleID", "timestamp", "udid"]
CSV.foreach('Old.csv', :headers=>true) do |row|
article_category_id = row['article_category_id'].to_i
articleID = row['articleID'].to_i
timestamp = row['timestamp'].to_i unless row['timestamp'].nil?
unless udids.include?(row['udid'])
udids << row['udid']
end
udid = udids.index(row['udid']) + 1
output_row = [article_category_id, articleID, timestamp, udid]
csv << output_row
end
end
How come this does not work? The CSV is there and has values, and I have 'require "csv" and time at the top, so good there. The problem seems to be with csv.each actually doing anything.
It returns
=> [] is the most common registration hour
=> [] is the most common registration day (Sunday being 0, Mon => 1 ... Sat => 7)
If there is any more info I can provide, please let me know.
#x = CSV.open \
'event_attendees.csv', headers: true, header_converters: :symbol
def time_target
y = []
#x.each do |line|
if line[:regdate].to_s.length > 0
y << DateTime.strptime(line[:regdate], "%m/%d/%y %H:%M").hour
y = y.sort_by {|i| grep(i).length }.last
end
end
puts "#{y} is the most common registration hour"
y = []
#x.each do |line|
if line[:regdate].to_s.length > 0
y << DateTime.strptime(line[:regdate], "%m/%d/%y %H:%M").wday
y = y.sort_by {|i| grep(i).length }.last
end
end
puts "#{y} is the most common registration day \
(Sunday being 0, Mon => 1 ... Sat => 7)"
end
making all the 'y's '#y's has not fixed it.
Here is sample from the CSV I'm using:
,RegDate,first_Name,last_Name,Email_Address,HomePhone,Street,City,State,Zipcode
1,11/12/08
10:47,Allison,Nguyen,arannon#jumpstartlab.com,6154385000,3155 19th St
NW,Washington,DC,20010
2,11/12/08
13:23,SArah,Hankins,pinalevitsky#jumpstartlab.com,414-520-5000,2022
15th Street NW,Washington,DC,20009
3,11/12/08 13:30,Sarah,Xx,lqrm4462#jumpstartlab.com,(941)979-2000,4175
3rd Street North,Saint Petersburg,FL,33703
Try this to load your data:
def database_load(arg='event_attendees.csv')
#contents = CSV.open(arg, headers: true, header_converters: :symbol)
#people = []
#contents.each do |row|
person = {}
person["id"] = row[0]
person["regdate"] = row[:regdate]
person["first_name"] = row[:first_name].downcase.capitalize
person["last_name"] = row[:last_name].downcase.capitalize
person["email_address"] = row[:email_address]
person["homephone"] = PhoneNumber.new(row[:homephone].to_s)
person["street"] = row[:street]
person["city"] = City.new(row[:city]).clean
person["state"] = row[:state]
person["zipcode"] = Zipcode.new(row[:zipcode]).clean
#people << person
end
puts "Loaded #{#people.count} Records from file: '#{arg}'..."
end