How to import a column of a CSV file into a Ruby array? - ruby

My goal is to import a one column of a CSV file into a Ruby array. This is for a self-contained Ruby script, not an application. I'll just be running the script in Terminal and getting an output.
I'm having trouble finding the best way to import the file and finding the best way to dynamically insert the name of the file into that line of code. The filename will be different each time, and will be passed in by the user. I'm using $stdin.gets.chomp to ask the user for the filename, and setting it equal to file_name.
Can someone help me with this? Here's what I have for this part of the script:
require 'csv'
zip_array = CSV.read("path/to/file_name.csv")
and I need to be able to insert the proper file path above. Is this correct? And how do I get that path name in there? Maybe I'll need to totally re-structure my script, but any suggestions on how to do this?

There are two questions here, I think. The first is about getting user input from the command line. The usual way to do this is with ARGV. In your program you could do file_name = ARGV[0] so a user could type ruby your_program.rb path/to/file_name.csv on the command line.
The next is about reading CSVs. Using CSV.read will take the whole CSV, not just a single column. If you want to choose one column of many, you are likely better off doing:
zip_array = []
CSV.foreach(file_name) { |row| zip_array << row[whichever_column] }

Okay, first problem:
a) The file name will be different on each run (I'm supposing it will always be a CSV file, right?)
You can solve this problem with creating a folder, say input_data inside your Ruby script. Then do:
Dir.glob('input_data/*.csv')
This will produce an array of ALL files inside that folder that end with CSV. If we assume there will be only 1 file at a time in that folder (with a different name), we can do:
file_name = Dir.glob('input_data/*.csv')[0]
This way you'll dynamically get the file path, no matter what the file is named. If the csv file is inside the same directory as your Ruby script, you can just do:
Dir.glob('*.csv')[0]
Now, for importing only 1 column into a Ruby array (let's suppose it's the first column):
require 'csv'
array = []
CSV.foreach(file_name) do |csv_row|
array << csv_row[0] # [0] for the first column, [1] for the second etc.
end
What if your CSV file has headers? Suppose your column name is 'Total'. You can do:
require 'csv'
array = []
CSV.foreach(file_name, headers: true) do |csv_row|
array << csv_row['Total']
end
Now it doesn't matter if your column is the 1st column, the 3rd etc, as long as it has a header named 'Total', Ruby will find it.
CSV.foreach reads your file line-by-line and is good for big files. CSV.read will read it at once but using it you can make your code more concise:
array = CSV.read(, headers: true).map do |csv_row|
csv_row['Total']
end
Hope this helped.

First, you need to assign the returned value from $stdin.gets.chomp to a variable:
foo = $stdin.gets.chomp
Which will assign the entered input to foo.
You don't need to use $stdin though, as gets will use the standard input channel by default:
foo = gets.chomp
At that point use the variable as your read parameter:
zip_array = CSV.read(foo)
That's all basic coding and covered in any intro book for a language.

Related

I want add ruby hash to a yaml file(need to add value to the same keys repeatedly)

I tried to write a yaml file from a hash using ruby. And am able to create the yaml file.
The program is just a report that i tried to create. But the real problem occurred is that it works perfectly for one date. When I tried to run the on day1, its work perfectly(the yaml file is created correctly), but when i tried to run on another date, the values in the yaml files are overwrite, but actually I want to add the new value with the previous one in the yaml.
I know my english is bad and sometimes little lack to create logics. Please help me to correct the issue. The code is below
def write_monthly_yaml_file(daily_data)
#daily = File.exist?(#monthly_yaml_file) ? YAML::load_file(#monthly_yaml_file) : Hash.new
#daily[Time.parse(#date).strftime("%m")] = daily_data
File.open(#monthly_yaml_file, "w") {|f| f.puts #daily.to_yaml}
end
here daily_data is the hash, will anyone please help me to add new daily_data with old one(I need to add each value with previous value like summing)
Thank you
I assume you want to have many entries for one month:
# the line below overwrites the value for the key given
# #daily[Time.parse(#date).strftime("%m")] = daily_data
# will collect all data in an array instead:
(#daily[Time.parse(#date).strftime("%m")] ||= []) << daily_data
Here we create an array as a value unless it existed and append the daily_data value to it. For this code to be run successfully, please remove your existing yaml file from the disk.
The reason is that currently there is a single instance of daily_data associated with the key and the interface changed.
If your data in #daily[day] is a number you want to add to, try this:
#daily = File.exist?(#monthly_yaml_file) ?
YAML::load_file(#monthly_yaml_file) : Hash.new
day = Time.parse(#date).strftime("%m")
#daily[day] = (#daily[day] + daily_data)
File.open(#monthly_yaml_file, "w") {|f| f.puts #daily.to_yaml}

Using CSV Class to parse a .csv file in Ruby

I'm using Ruby 1.9.3 and I've discovered the CSV class, but I can't get it to work. Basically, I want to be able to manipulate the various options for the CSV, and then pull a .csv file into an array to work with, eventually pushing that array back out into a new file.
This is what I have currently:
require 'csv'
CSV_Definition = CSV.New(:header_converters => :symbol)
CSV_Total = CSV.Read(File.Path("C:\Scripts\SQL_Log_0.csv"))
However, I don't think this is the right way to change the :header_converters. Currently I can't get IRB working to parse these pieces of code (I'm not sure how to require 'csv' in IRB) so I don't have any particular error message. My expectations for this will be to create an array (CSV_Total) that has a header with no symbols in it. The next step is to put that array back into a new file. Basically it would scrub CSV files.
Ruby used to have it's own built in CSV library which has been replaced with FasterCSV as of version 1.9, click on the link for documentation.
All that's required on your part is to use to import the CSV class via require 'csv' statement wherever you want to use it and process accordingly. It's pretty easy to build an array with the foreach statement, e.g.,:
people.csv
Merry,Christmas
Hal,Apenyo
Terri,Aki
Willy,Byte
process_people.rb
require 'csv'
people = []
CSV.foreach(File.path("people.csv")) do |row|
# Where row[i] corresponds to a zero-based value/column in the csv
people << [row[0] + " " + row[1]]
end
puts people.to_s
=> [["Merry Christmas"], ["Hal Apenyo"], ["Terri Aki"], ["Willy Byte"]]

Ruby self-editing source code

I am creating a grammar corrector app. You input slang and it returns a formal English correction. All the slang words that are supported are kept inside arrays. I created a method that looks like this for when a slang is entered that is not supported.
def addtodic(lingo)
print"\nCorrection not supported. Please type a synonym to add '#{lingo}' the dictionary: "
syn = gets.chomp
if $hello.include?("#{syn}")
$hello.unshift(lingo)
puts"\nCorrection: Hello.\n"
elsif $howru.include?("#{syn}")
$howru.unshift(lingo)
puts"\nCorrection: Hello. How are you?\n"
end
end
This works, but only until the application is closed. how can I make this persist so that it amends the source code as well? If I cannot, how would I go about creating an external file that holds all of the cases and referencing that in my source code?
You will want to load and store your arrays in a external file.
How to store arrays in a file in ruby? is relevant to what you are trying to do.
Short example
Suppose you have a file that has one slang phrase per line
% cat hello.txt
hi
hey
yo dawg
The following script will read the file into an array, add a term, then write the array to a file again.
# Read the file ($/ is record separator)
$hello = File.read('hello.txt').split $/
# Add a term
$hello.unshift 'hallo'
# Write file back to original location
open('hello.txt', 'w') { |f| f.puts $hello.join $/ }
The file will now contain an extra line with the term you just added.
% cat hello.txt
hallo
hi
hey
yo dawg
This is just one simple way of storing an array to file. Check the link at the beginning of this answer for other ways (which will work better for less trivial examples).

Ruby Appending an hash and saving it in a CSV

I am learning ruby from a book I got called The Pragmatic Programmers Guide and have got to a point where I'm reading and processing things from a .csv file. I taken upon myself the challenge of making a small program that opens a csv file and then reads all the data, saving it into a hash. This is my code so far:
require 'csv'
class NoxReader
phash = {}
def open
CSV.foreach('data.csv', headers: true) do |row|
row.each do |x|
name, password = line.chomp.split(",")
phash[name] = password
end
end
end
end
Now I want to be able to append to that hash and write it back to the csv file. I have an idea on how to write it back to csv, but it's just appending to the hash via a gets.chomp that blows me away. Any help on where to start would be much appreciated.
In fact you are already appending key-value pairs to your hash. This is what phash[name] = password does in your code.
If you want to add the resulting hash of your function login_prompt in your other question to phash, you need to
phash.merge login_prompt

Ruby parse comma separated text file

I need some help with a Ruby script I can call from the console. The script needs to parse a simple .txt file with comma separated values.
value 1, value2, value3, etc...
The values needs to be added to the database.
Any suggestions?
array = File.read("csv_file.txt").split(",").map(&:strip)
You will get the values in the array and use it to store to database. If you want more functions, you can make use of FasterCSV gem.
Ruby 1.9.2 has a very good CSV library which is useful for this stuff: http://www.ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html
On earlier versions of Ruby you could use http://fastercsv.rubyforge.org/ (which essentially became CSV in 1.9.2)
You could do it manually by reading the file into a string and using .split(',') but I'd go with one of the libraries above.
Quick and dirty solution:
result = []
File.open("<path-to-file>","r") do |handle|
handle.each_line do |line|
result << line.split(",").strip
end
end # closes automatically when EOF reached
result.flatten!
result # => big array of values
Now you can iterate the result array and save the values to the database.
This simple file iteration doesn't take care for order or special fields, because it wasn't mentioned in the question.
Something easy to get you started:
IO.readlines("csv_file.txt", '').each do |line|
values = line.split(",").collect(&:strip)
# do something with the values?
end
Hope this helps.

Resources