Ruby .each method on Array from split string - arrays

I'm having trouble using the .each method on an array that results of a string.split
def my_function(str)
words = str.split
return words #=> good, morning
return words[words.count-1] #=> morning
words.each do |word|
return word
end
end
puts my_function("good morning") #=> good
With any multi-word string, I only get the 1st word, not each of the words. With this example, I don't understand why I don't get "good" and "morning" when the 2nd item clearly exists in the array.
Similarly, using a while loop gave me the same result.
def my_function(str)
words = str.split
i = 0
while i < words.count
return word[i]
i += 1
end
puts my_function("good morning") # => good
Any help is appreciated. Thanks in advance!

The return statement in ruby is used to return one or more values from a Ruby Method. So your method will exit from return words.
def my_function(str)
words = str.split
return words # method will exit from here, and not continue, but return value is an array(["good", "morning"]).
return words[words.count-1] #=> morning
....
end
puts my_function("good morning")
output:
good
morning
if you want to use each method to output words, you can do like this:
def my_function(str)
str.split.each do |word|
puts word
end
end
or
def my_function(str)
str.split.each { |word| puts word }
end
my_function("good morning")
output:
good
morning

You are assuming that return words returns the array to your outer puts function which is true. However once you return, you leave the function and never go back unless you explicitly call my_function() again (which you aren't) in which case you would start from the beginning of the function again.
If you want to print the value while staying in the function you will need to use
def my_function(str)
words = str.split
puts words #=> good, morning
puts words[words.count-1] #=> morning
words.each do |word|
puts word # print "good" on 1st iteration, "morning" on 2nd
end
end
my_function("good morning")

Related

Selecting a single element from an array, within an "if" statement

Creating a method that receives input from a user -- and if said input includes any word from a predetermined array, it prints the word "success!" Otherwise, if the input doesn't include a word from that array, it prints the word "failure."
My ideal would be to create a scenario where I can populate the array with as many elements as I want, and the method will always reference that array when deciding how to react to the user's input.
When I run it, however, I get an error message saying "no implicit conversion of Array into String."
My code is below. Appreciate any and all help! Thanks.
def hello
word_bank = ["hello", "hi", "howdy"]
print "Say a word: "
greeting = $stdin.gets.chomp.to_s
if greeting.include?(word_bank[0..2])
puts "success!"
else
puts "failure."
end
end
hello
include? is an array's method.
word_bank = ["hello", "hi", "howdy"]
print "Say a word: "
greeting = gets.chomp
if word_bank.include?(greeting)
puts "success!"
else
puts "failure."
end
puts [1,2,3].include?(1) # true
puts [1,2,3].include?(4) # false
If word_bank was big, for performance reason we should use a set instead of an array.
require 'set'
word_bank = Set.new(["hello", "hi", "howdy"])
This is how I'd solve the issue, I haven't tested it though but it should work.
def hello
word_bank = ['hello', 'hi', 'howdy']
print 'Say a word: '
greeting = $stdin.gets.chomp.to_s
word_bank.each do |w|
w == greeting ? (puts 'success') : (puts 'failure')
end
end

Print elements of ruby array line by line after splitting a single string with "\n" condition

I have a single string, achieved using backticks of the following form:
output = `git log`
then, I have splitted the result where there are "\n" and the result went into an array of the form:
array = output.split("\n")
then, I am just trying to output the result in the screen, however, when I am using
array.each do |a|
puts a
end
I am getting as a result a double line of the form:
result after puts
(empty line)
result after puts etc
when my preferred result is a single line of the form:
result after puts
result afters puts etc
I tried to perform this with print, but I am getting:
result after puts result after puts etc
in a single line.
Can you please help me?
The issue is when you split using \n, if there are two \n characters then an empty "" gets added to the array.
eg: test = ["this","","is","test"]
Now if you do,
test.each do |a|
puts a
end
The o/p will be,
this
// a new line will come here.
is
test
so you should reject the empty values,
test2 = test.reject{ |value| value == ""}
test2.each do |a|
puts a
end
Result is,
this
is
test
In same way,
output = `git log`
array = output.split("\n")
array2 = array.reject{ |value| value == ""}
array2.each do |a|
puts a
end
This will give you the correct result.
Thanks to #AndreyDeineko, we have that:
"The issue is when you split using \n if there are two \n characters then an empty "" gets added to the array. Howcome? a = "1\n2\n3\n4\n"; a.split("\n") #=> ["1", "2", "3", "4"].
Therefore, array.each { |a| a } will work for you"
It did not work 100% for me, but using his answer, I manage to achieve the required result which is:
array.each { |a| a }
puts array

How to make an array of class objects in ruby

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.
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.
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.
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
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
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

Return unique values of an array without using `uniq`

For a challenge, I'm trying to return the unique values of an array without using uniq. This is what I have so far, which doesn't work:
def unique
unique_arr = []
input_arr.each do |word|
if word != unique_arr.last
unique_arr.push word
end
end
puts unique_arr
end
input = gets.chomp
input_arr = input.split.sort
input_arr.unique
My reasoning here was that if I sorted the array first before I iterated through it with each, I could push it to unique_arr without repetition being a possibility considering if it's a duplicate, the last value pushed would match it.
Am I tackling this the wrong way?
Yes, you are making at least two mistakes.
If you want to call it as input_arr.unique with input_arr being an array, then you have to define the method on Array. You have input_arr within your method body, which comes from nowhere.
puts in the last line of your code outputs to the terminal, but makes the method return nil, which makes it behave differently from uniq.
It can be fixed as:
class Array
def unique
unique_arr = []
each do |word|
unique_arr.push(word) unless unique_arr.last == word
end
unique_arr
end
end
A unique array? That sounds like a Set to me:
require 'set'
Set.new([1,2,3,2,3,4]).to_a
#=> [1,2,3,4]
Here's a concise way to do it that doesn't explicitly use functionality from another class but probably otherwise misses the point of the challenge:
class Array
def unique
group_by(&:itself).keys
end
end
I try this three options. Just for challenge
class Array
def unique
self.each_with_object({}) { |k, h| h[k] = k }.keys
end
def unique2
self.each_with_object([]) { |k, a| a << k unless a.include?(k) }
end
def unique3
arr = []
self.map { |k| arr << k unless arr.include?(k) }
arr
end
end
Here is one more way to do this:
uniques = a.each.with_object([]) {|el, arr| arr << el if not arr.include?(el)}
That's so easy if you see it this way:
a = [1,1,2,3,4]
h = Hash.new
a.each{|q| h[q] = q}
h.values
and this will return:
[1, 2, 3, 4]

Adding items to a new array with index

Trying to make a method skip_animals that takes an animals array and a skip integer and returns an array of all elements except first skip number of items.
input: skip_animals(['leopard', 'bear', 'fox', 'wolf'], 2)
expected output: ["2:fox", "3:wolf"]
def skip_animals(animals, skip)
arr = Array.new
animals.each_with_index{|animal, index| arr.push("#{animal}:#{index}") }
puts arr.drop(skip)
end
This instead puts each output on a separate line and doesn't add them to the array arr. I thought the arr.push would add them correctly. What do I have to do to get the elements added to the array?
I want to use these methods, not map or something more advanced. I need to tinker with this each_with_index line, not overhaul it.
(This is a challenge on Hackerrank, so it uses STDIN and STDOUT)
EDIT
Here is my updated code with p instead of puts. It's giving me a weird output of two different arrays, not sure why.
def skip_animals(animals, skip)
arr = Array.new
animals.each_with_index{|animal, index| arr.push("#{index}:#{animal}") }
p arr.drop(skip)
end
This gives me two lines of output:
["3:panda", "4:tiger", "5:deer"]
["0:leopard", "1:bear", "2:fox", "3:wolf", "4:dog", "5:cat"]
I'm assuming the top is the correct array, but I don't get why the second is printing also, or why it has a different set of animals.
Use p instead of puts.
irb(main):001:0> puts ['1', '2']
1
2
=> nil
irb(main):002:0> p ['1', '2']
["1", "2"]
According to the documentation, puts:
Writes the given objects to ios as with IO#print. Writes a record
separator (typically a newline) after any that do not already end with
a newline sequence. If called with an array argument, writes each
element on a new line. If called without arguments, outputs a single
record separator.
BTW, I would code like this (using Enumerable#map + returning result instead of printing inside the function):
def skip_animals(animals, skip)
animals.drop(skip).each_with_index.map { |animal, index|
("#{index + skip}:#{animal}")
}
end
p skip_animals(['leopard', 'bear', 'fox', 'wolf'], 2)
just remove puts remove form this line puts arr.drop(skip)
def skip_animals(animals, skip)
arr = Array.new
animals.each_with_index{|animal, index| arr.push("#{animal}:#{index}") }
arr.drop(skip)
end

Resources