Reputation: 31
I'm trying to make an array of class objects, but my code doesn't work. When I make a Solution.new it returns nil, and I want it returns an array of arrays from words in each line of test.txt
.
I'm using Ruby 2.1.5
class Line
def initialize (content)
@content = content
self.line_arr
end
def line_arr
@content.split
end
end
class Solution
def read_file
array = []
File.foreach('test.txt') do |line|
array << Line.new(line)
end
end
end
And now when I make a
foo = Solution.new
foo.read_file
it returns nil
.
Upvotes: 2
Views: 1510
Reputation: 361
class Line
attr_reader :content
def initialize (content)
@content = content.split(' ')
end
end
class Solution
def read_file
array = []
File.foreach('test.txt') do |line|
array << Line.new(line).content
end
array
end
end
You need to add this 'array' row, because you need to return it from the method call. Also I simplified a bit the Line class here. Basically, this code can solve your problem, but consider using the regular expression for parsing rows.
Upvotes: 0
Reputation: 11235
I don't think Solution.new
is returning nil
in your example, it's returning a new instance of solution (foo
in your example)
Your main issue is that read_file
is returning the value of File.foreach
, which is always nil
.
For starters, update your read_file
method to return the array itself:
class Solution
def read_file
array = []
lines = []
File.foreach('test.txt') do |line|
lines << Line.new(line)
end
array << lines
array
end
end
solution = Solution.new
solution.read_file
# outputs:
# [#<Line:0x007fab92163b50 @content="This Is A Line\n">, #<Line:0x007fab92161be8 @content="Line 2\n">, #<Line:0x007fab92160d88 @content="Line3">]
If you want to return an array of arrays split each line by whitespace:
class Solution
def read_file
lines = []
File.foreach('test.txt') do |line|
words = []
line.strip.split(/\s+/).each do |word|
words << word
end
lines << Line.new(words)
end
lines
end
end
The key line of code here is: line.strip.split(/\s+/)
which first strips leading and trailing whitespace from the string, then converts it to an array by splitting the string based on whitespace (the /s+/
regex matches one or more blank characters).
Some other suggestions:
Pass the filename as an argument to read_file
you can set a default argument if you want to:
class Solution
def read_file(filename = 'test.txt')
array = []
File.foreach(filename) do |line|
array << Line.new(line)
end
array
end
end
Finally, for a much more elegant solution, you can use map
, and simply call .split
to return a nested array. The Line
class isn't really doing much in this case.
class Solution
def read_file
File.foreach('test.txt').map do |line|
line.strip.split(/\s+/)
end
end
end
This will simply return an array of arrays, where the inner array contains the words for each line.
Upvotes: 3
Reputation: 4970
If all you need to do is get arrays of words, and you don't mind loading the entire file into memory at once, then it can be done very simply with the code below (the 3 lines beginning with word_arrays = ...
, the rest are setup and output):
#!/usr/bin/env ruby
File.write('woods.txt',
"The woods are lovely, dark, and deep
But I have promises to keep
And miles to go before I sleep
And miles to go before I sleep")
word_arrays = File.readlines('woods.txt').each_with_object([]) do |line, word_arrays|
word_arrays << line.split
end
word_arrays.each.with_index do |words, index|
puts "#{index}: #{words} "
end
=begin
Prints:
0: ["The", "woods", "are", "lovely,", "dark,", "and", "deep"]
1: ["But", "I", "have", "promises", "to", "keep"]
2: ["And", "miles", "to", "go", "before", "I", "sleep"]
3: ["And", "miles", "to", "go", "before", "I", "sleep"]
=end
Upvotes: 0
Reputation: 121000
Consider to use Enumerable#inject
instead of creating unnecessary variables:
class Solution
def read_file
File.foreach('test.txt').inject([]) do |memo, line|
memo << Line.new(line)
end
end
end
or, in this particular case, map
will do the trick:
class Solution
def read_file
File.foreach('test.txt').map &Line.method(:new)
end
end
Upvotes: 0
Reputation: 375
Try this:
class Line
def initialize (content)
@content = content
self.line_arr
end
def line_arr
@content.split
end
end
class Solution
def initialize
self.read_file
end
def read_file
array = []
File.foreach('test.txt') do |line|
array << Line.new(line)
end
array
end
end
Upvotes: 0