I've been trying to open a file, read the contents and then numbering the contents of that file and saving it. So for example the file contains:
This is line 1.
This is line 2.
This is line 3.
the output should be :
This is line 1.
This is line 2.
This is line 3.
I'm incredibly new to ruby so I've only gotten as far as adding the lines to an array. But now I don't know how to add numbers to each item of the array. Here is what I have:
class AddNumbers
def insert_numbers_to_file(file)
#file_array = []
line_file = File.open(file)
line_file.each do |line|
#file_array << [line]
end
end
end
Any help or hints would be appreciated.
Thank you
Enumerators have an #each_with_index method that you can use:
class AddNumbers
def insert_numbers_to_file(file)
#file_array = []
File.open(file).each_with_index do |line, index|
#file_array << "%d. %s" % [index, line]
end
end
end
The magic variable $. is your ticket to ride here:
class AddNumbers
def insert_numbers_to_file(file)
#file_array = []
line_file = File.open(file)
line_file.each do |line|
#file_array << "#{$.}: #{line}"
end
#file_array
end
end
Related
I have a list of names (names.txt) separated by line. After I loop through each line, I'd like to move it to another file (processed.txt).
My current implementation to loop through each line:
open("names.txt") do |csv|
csv.each_line do |line|
url = line.split("\n")
puts url
# Remove line from this file amd move it to processed.txt
end
end
def readput
#names = File.readlines("names.txt")
File.open("processed.txt", "w+") do |f|
f.puts(#names)
end
end
You can do it like this:
File.open('processed.txt', 'a') do |file|
open("names.txt") do |csv|
csv.each_line do |line|
url = line.chomp
# Do something interesting with url...
file.puts url
end
end
end
This will result in processed.txt containing all of the urls that were processed with this code.
Note: Removing the line from names.txt is not practical using this method. See How do I remove lines of data in the middle of a text file with Ruby for more information. If this is a real goal of this solution, it will be a much larger implementation with some design considerations that need to be defined.
I am trying to scrape list of restaurants for my zip code from Deliveroo.co.uk
I need to add a way to figure out whether a restaurant is open or closed... from the website its very clear, but I just need to update my code to reflect this.
How do I go about doing this? I need to create something like a 'status' variable and then set each restaurant to 'open' or 'closed'.
Here is the website I'm trying to scrape from: https://deliveroo.co.uk/restaurants/london/maida-vale?postcode=W92DE&time=1800&day=today
And my code is below.
thanks.
require 'open-uri'
require 'nokogiri'
require 'csv'
# Store URL to be scraped
url = "https://deliveroo.co.uk/restaurants/london/maida-vale?postcode=W92DE"
# Parse the page with Nokogiri
page = Nokogiri::HTML(open(url))
# Display output onto the screen
name =[]
page.css('span.list-item-title.restaurant-name').each do |line|
name << line.text
end
category = []
page.css('span.restaurant-detail.detail-cat').each do |line|
category << line.text
end
delivery_time = []
page.css('span.restaurant-detail.detail-time').each do |line|
delivery_time << line.text
end
distance = []
page.css('span.restaurant-detail.detail-distance').each do |line|
distance << line.text
end
status = []
# Write data to CSV file
CSV.open("deliveroo.csv", "w") do |file|
file << ["Name", "Category", "Delivery Time", "Distance", "Status"]
name.length.times do |i|
file << [name[i], category[i], delivery_time[i], distance[i]]
end
end
end
We need to check li.restaurant--details have / have not class unavailable for close / open restaurant.
status = []
page.css('li.restaurant--details').each do |line|
if line.attr("class").include? "unavailable"
sts = "closed"
else
sts = "open"
end
status << sts
end
Btw, you should remove white space when get restaurant_name, etc ...
page.css('span.list-item-title.restaurant-name').each do |line|
name << line.text.strip
end
You can refer my code at here: https://gist.github.com/vinhnglx/4eaeb2e8511dd1454f42
I'm trying to input text from a file, ignoring the first line, and adding each character to a 2D array at a separate index [[],[]]. So far I can add the characters to their own index but can't remove the newline characters with .chomp or etc.
I want my end result to be
[['*','.','.','.']","['.','.','*','.']","['.','.','.','.']]
So that [0][0] will return * for example, and [0] will return *...
Right now I'm returning
[['*','.','.','.',"\n"]","['.','.','*','.',"\n"]","['.','.','.','.',"\n"]]
The code in question is:
def load_board(file)
board = File.readlines(file)[1..-1].map do |line|
line.split("").map(&:to_s)
end
end
origin_board = load_board('mines.txt')
print origin_board
If I try the following code:
def load_board(file)
board = File.readlines(file)[1..-1].map do |line|
line.split.map(&:to_s)
end
end
origin_board = load_board('mines.txt')
print origin_board
I end up with a 2D array like:
[["*..."],["..*."],["...."]]
Stripping your input should help:
def load_board(file)
board = File.readlines(file)[1..-1].map do |line|
# ⇓⇓⇓⇓⇓
line.strip.split("").map(&:to_s)
end
end
String#strip will remove leading-trailing blanks from a string. The other option is not to use readlines in favour of read and split by $/ (line separator):
def load_board(file)
board = File.read(file).split($/)[1..-1].map do |line|
line.split("").map(&:to_s)
end
end
You can add a .chomp before the .split, like this:
def load_board(file)
board = File.readlines(file)[1..-1].map do |line|
line.chomp.split("").map(&:to_s)
end
end
Haven't exactly tested it but did some fiddling and it should work http://repl.it/hgJ/1.
I have been facing some issue with file concepts. I have a text file in which I have 1000 lines. I want to split that file into 2 and each of which should contain 500 lines.
For that I wrote the following code, but it splits that by giving certain memory space.
class Hello
def chunker f_in, out_pref, chunksize = 500
File.open(f_in,"r") do |fh_in|
until fh_in.eof?
ch_path = "/my_applications//#{out_pref}_#{"%05d"%(fh_in.pos/chunksize)}.txt"
puts "choose path: "
puts ch_path
File.open(ch_path,"w") do |fh_out|
fh_out << fh_in.read(chunksize)
puts "FH out : "
puts fh_out
end
end
end
end
end
f=Hello.new
f.chunker "/my_applications/hello.txt", "output_prefix"
I am able to split the parent file according to memory size(500kb).
But I want that gets splitted by number of lines. How can I achieve that.
Please help me.
Calculating the middle line pivot, and output according it.
out1 = File.open('output_prefix1', 'w')
out2 = File.open('output_prefix2', 'w')
File.open('/my_applications/hello.txt') do |file|
pivot = file.lines.count / 2
file.rewind
file.lines.each_with_index do |line, index|
if index < pivot
out1.write(line)
else
out2.write(line)
end
end
end
out1.close
out2.close
file = File.readlines('hello.txt')
File.open('first_half.txt', 'w') {|new_file| new_file.puts file[0...500]}
File.open('second_half.txt', 'w') {|new_file| new_file.puts file[500...1000]}
I am using the code from this tutorial to parse a CSV file and add the contents to a database table. How would I ignore the first line of the CSV file? The controller code is below:
def csv_import
#parsed_file=CSV::Reader.parse(params[:dump][:file])
n = 0
#parsed_file.each do |row|
s = Student.new
s.name = row[0]
s.cid = row[1]
s.year_id = find_year_id_from_year_title(row[2])
if s.save
n = n+1
GC.start if n%50==0
end
flash.now[:message] = "CSV Import Successful, #{n} new students added to the database."
end
redirect_to(students_url)
end
This question kept popping up when i was searching for how to skip the first line with the CSV / FasterCSV libraries, so here's the solution that if you end up here.
the solution is...
CSV.foreach("path/to/file.csv",{:headers=>:first_row}) do |row|
HTH.
#parsed_file.each_with_index do |row, i|
next if i == 0
....
If you identify your first line as headers then you get back a Row object instead of a simple Array.
When you grab cell values, it seems like you need to use .fetch("Row Title") on the Row object.
This is what I came up with. I'm skipping nil with my if conditional.
CSV.foreach("GitHubUsersToAdd.csv",{:headers=>:first_row}) do |row|
username = row.fetch("GitHub Username")
if username
puts username.inspect
end
end
Using this simple code, you can read a CSV file and ignore the first line which is the header or field names:
CSV.foreach(File.join(File.dirname(__FILE__), filepath), headers: true) do |row|
puts row.inspect
end
You can do what ever you want with row. Don't forget headers: true
require 'csv'
csv_content =<<EOF
lesson_id,user_id
5,3
69,95
EOF
parse_1 = CSV.parse csv_content
parse_1.size # => 3 # it treats all lines as equal data
parse_2 = CSV.parse csv_content, headers:true
parse_2.size # => 2 # it ignores the first line as it's header
parse_1
# => [["lesson_id", "user_id"], ["5", "3"], ["69", "95"]]
parse_2
# => #<CSV::Table mode:col_or_row row_count:3>
here where it's the fun part
parse_1.each do |line|
puts line.inspect # the object is array
end
# ["lesson_id", "user_id"]
# ["5", " 3"]
# ["69", " 95"]
parse_2.each do |line|
puts line.inspect # the object is `CSV::Row` objects
end
# #<CSV::Row "lesson_id":"5" "user_id":" 3">
# #<CSV::Row "lesson_id":"69" "user_id":" 95">
So therefore I can do
parse_2.each do |line|
puts "I'm processing Lesson #{line['lesson_id']} the User #{line['user_id']}"
end
# I'm processing Lesson 5 the User 3
# I'm processing Lesson 69 the User 95
data_rows_only = csv.drop(1)
will do it
csv.drop(1).each do |row|
# ...
end
will loop it