RUBY: Read text file into 2D array, while also removing newlines? - ruby-on-rails

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.

Related

Move line from one text file to another

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.

prepending numbers to a file

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

How to split a text file into 2 files using number of lines?

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]}

Rails - New line character at the end of row in CSV import causing errors

I'm running a rake task to import some file attributes and I'm receiving an error that would lead me to believe that the string created for each line contains some sort of new-line character (e.g. /n).
EDIT - New-line character has been confirmed to be the issue.
Here is a sample of what my CSV file might look like:
1|type1,type2|category1
2|type2|category1,category2,category3
3|type2,type4|category3,category8
And here is my code to deal with it:
namespace :data do
desc "import"
task :import => :environment do
file = File.open(Rails.root.join('lib/assets/data.csv'), 'r')
file.each do |line|
attrs = line.split("|")
foo = Model.find(attrs[0])
attrs[1].split(",").each do |type|
foo.add_type!(ModelType.find_by_name(type))
end
attrs[2].split(",").each do |category|
foo.categorize!(ModelCategory.find_by_name(category))
end
end
end
end
ModelType and ModelCategory are both seperate models with a :through relationship to Model that is built with the function Model.add_type! and Model.categorize!.
When I run rake data:import, everything works fine up until the final category is reached at the end of the first line. It doesn't matter which category it is, nor how many categories are present in attrs[2] - it only fails on the last one. This is the error I receive:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Any thoughts on how to fix this or avoid this error?
You can use chomp:
attrs = line.chomp.split("|")
attrs = line.split("|")
if attrs.length > 0
foo = Model.find(attrs[0])
...
end
You probably have an empty line at the end of your CSV
UPDATE
file = File.open(Rails.root.join('lib/assets/data.csv'), 'r')
file.split("\r\n").each do |line|
or
file = File.open(Rails.root.join('lib/assets/data.csv'), 'r')
file.split("\r").each do |line|
or
file = File.open(Rails.root.join('lib/assets/data.csv'), 'r')
file.split("\n").each do |line|
depending on how the CSV was originally generated!
Use String.encode(universal_newline: true) instead gsub.
It converting CRLF and CR to LF # Always break lines with \n

How to simplify this Rails code -- gets first line from file, parses it and downcases each element

fields = CSV.parse(File.open(filename).first)[0]
fields.each_with_index do |field, i|
fields[i] = field.downcase
end
I want to get the first line from the line, parse it as CSV and make each element lowercase.
This code seems too redundant to me. Any suggestions?
You can make the looping stuff a bit more concise if you wish:
fields.map!(&:downcase)
or even:
fields = CSV.parse(File.open(filename).first)[0].map(&:downcase)
I think you're leaving a file handle hanging there too so you might want to try something like:
fields = []
File.open(filename) do |f|
fields = CSV.parse(f.readline)[0].map(&:downcase)
end
I don't think there's anything wrong with what you have but you could say this:
fields = CSV.parse(File.open(filename, 'r').first).first.map(&:downcase)
Or you could make it easier to read with some methods:
def first_line_of(filename)
File.open(filename, 'r').first
end
def csv_to_array(string)
CSV.parse(string).first
end
def downcase(a)
a.map(&:downcase)
end
fields = downcase csv_to_array first_line_of filename

Resources