Learning Ruby - Stuck on string comparison within an array - ruby

I'm working through Learning to Program with Ruby and I am stuck on building my own sort method.
I'm struggling to figure out why the comparison method inside my recursive_sort is throwing out an error
chapter10.rb:120:in `block in recursive_sort': undefined method `<' for ["zebra"]:Array (NoMethodError)
But this works just fine...
lowest = 'zebra'
if 'cat' < 'zebra'
lowest = 'cat'
end
puts lowest
Could someone put in the right direction to something that can help me wrap my head around this? Thanks!
puts 'Sorting Program with recursion v1.0'
# Keep two more lists around
# One for already-sorted words
# One for still - unsorted words
# Find the smallest word in the unsorted list
# push it into the end of the sorted_array
def sort some_array
recursive_sort some_array, []
end
def recursive_sort unsorted_array, sorted_array
lowest = unsorted_array[0]
unsorted_array.each do |uns|
if uns < lowest
lowest = uns
end
end
puts lowest
end
# Get a list of unsorted words into an array
orig_array = []
word = 'placeholder'
puts 'Enter a list of words to be sorted. Press enter when done.'
while word != ''
word = gets.chomp
orig_array.push [word]
end
orig_array.pop
puts 'This is the output of the built in sort method.'
orig_array.sort.each do |un|
puts un
end
puts 'This is the output of Rick\'s sort method.'
sort orig_array

orig_array.push [word]
Here, you are actually pushing an array into an array, so that your orig_array becomes
[["word 1"], ["word 2"], ["word 3"], ...]
Remove the [] around word to fix this, or change the .push to += or .concat, which will glue together the two arrays.

Related

Swap adjacent elements in array

I am trying to build a method in Ruby that will take in a string that has been split into an array of letters and then iterate through the array, swapping the element at index n with that at index n+1. The method will then join the new array into a string and push it to another array.
Here is an example of what I am looking to do:
string = "teh"
some_method(string)
some ruby magic here
array << new_string
end
Expected output:
["eth", "the"]
This is for a spell checker program I am writing for school. The method will check if letters in a misspelled word are swapped by checking to see if the output array elements are in the dictionary. If they are, it will return the word with that is most likely the correct word. I haven't had any luck finding articles or documentation on how to build such a method in ruby or on an existing method to do this. I've been tinkering with building this method for awhile now but my code isn't behaving anything like what I need. Thanks in advance!
As #Sergio advised, you want to use parallel assignment for this:
def reverse_em(str)
(0...str.size-1).map do |i|
s = str.dup
s[i], s[i+1] = s[i+1], s[i]
s
end
end
candidates = reverse_em "alogrithm"
#=> ["laogrithm", "aolgrithm", "algorithm", "alorgithm",
# "alogirthm", "alogrtihm", "alogrihtm", "alogritmh"]
dictionary_check(candidates)
#=> algorithm
# al·go·rithm
# noun \ˈal-gə-ˌri-thəm\
# a set of steps that are followed in order to solve a
# mathematical problem or to complete a computer process
Without splitting it into arrays then joining to new arrays (because that doesn't seem necessary):
def some_method(string)
swapped_strings = []
(0...string.size-1).each do |i|
temp_string = string.dup
temp_string[i], temp_string[i+1] = temp_string[i+1], temp_string[i]
swapped_strings << temp_string
end
swapped_strings
end

Nested Data Structures: Why is my Hash turning into an Array of an Array?

For an assignment I am working on, I'm trying to sort words in a piece of text by frequency of words in the text. I have a function that almost accomplishes what I'd like to do but not quite. Below is my code:
require 'pry'
def top_words(words)
word_count = Hash.new(0)
words = words.split(" ")
words.each { |word| word_count[word] += 1 }
word_count = word_count.sort_by do |words, frequencies|
frequencies
end
binding.pry
word_count.reverse!
word_count.each { |word, frequencies| puts word + " " + frequencies.to_s }
end
words = "1st RULE: You do not talk about FIGHT CLUB.
2nd RULE: You DO NOT talk about FIGHT CLUB.
3rd RULE: If someone says 'stop' or goes limp, taps out the fight is over.
4th RULE: Only two guys to a fight.
5th RULE: One fight at a time.
6th RULE: No shirts, no shoes.
7th RULE: Fights will go on as long as they have to.
8th RULE: If this is your first night at FIGHT CLUB, you HAVE to fight."
For some reason, the sort_by method above my binding.pry is changing the structure of my Hash into an array of an array. Why?
What I'd like to do is to sort the words within a hash and then grab the top three words from the Hash. I've yet to figure out how to do this but I'm pretty sure I can do this once I've sorted the array of an array problem.
Now, I suppose I could grab them using .each and array[0].each { |stuff| puts stuff[0] + stuff[1] } but I don't think that is the most efficient way. Any suggestions?
For some reason, the sort_by method above my binding.pry is changing the structure of my Hash into an array of an array. Why?
Explanation is below :
sort_by { |obj| block } → array method give always array.
The current implementation of sort_by generates an array of tuples containing the original collection element and the mapped value. This makes sort_by fairly expensive when the keysets are simple.
Now in your case word_count is a Hash object, thus sort_by is giving you like - [[key1,val],[key2,val2],..]. This is the reason you are getting array of array.
What I'd like to do is to sort the words within a hash and then grab the top three words from the Hash. I've yet to figure out how to do this but I'm pretty sure I can do this once I've sorted the array of an array problem.
Yes, possible.
sorted_array_of_array = word_count.sort_by do |words, frequencies| frequencies }
top_3_hash = Hash[ sorted_array_of_array.last(3) ]
I would write the code as below :
def top_words(words)
# splitting the string words on single white space to create word array.
words = words.split(" ")
# creating a hash, which will have key as word and value is the number of times,
# that word occurred in a sentence.
word_count = words.each_with_object(Hash.new(0)) { |word,hash| hash[word] += 1 }
# sorting the hash, to get a descending order sorted array of array
sorted_array_of_array = word_count.sort_by { |words, frequencies| frequencies }
# top 3 word/frequency is taken from the sorted list. Now reading them from last
# to show the output as first top,second top and so on..
sorted_array_of_array.last(3).reverse_each do |word, frequencies|
puts "#{word} has #{frequencies}"
end
end

Why is the method deleting the element inside my array?

I'm trying to create my own .sort method as an exercise in a ruby book, using recursion, and for some reason they haven't taught me the spaceship operator yet. My code works to get the smallest value - apple - and puts it in the sorted array, and it even repeats using the recursion, and resets the array to repeat the process to add the second smallest word. The problem is for some reason it removes the smallest word -apple- and I can't figure out why. I know where I think - in the else myArray.length == 1 statement when I pop the element off the array, but why is it removing from the sortedArray too?
sortedArray ends up with value apple, then when it does recursion it SHOULD be sortedArray = ['apple', 'banana' …] but it removes apple, then it removes banana etc… until I end up with sortedArray = ['quincy']
I have tried moving my arrays to multiple places, and I've tried adding to the sortedWords array in multiple places but it is always deleting or resetting the sortedWords array.
It looks like I'm really close since I've got the alphabetizing working. How do I get it to add all the items to the sortedWords array?
ArrayofWords = ['cat', 'dog', 'bat', 'elephant', 'apple', 'banana', 'quincy', 'boo']
# Why is it deleting, or replacing my sortedWords array? If you run this code you will notice that the sortedWords array
# is giving me the smallest word in the array, but then I add the recursive part, and somehow the previous smallestword
#gets deleted... but I have never in any part of my code say delete or replace the sorted array...
def sortTheArray myArray
unsortedWords = []
sortedWords = []
smallestValue = ''
while myArray.length != 0
if myArray.first < myArray.last
unsortedWords.push(myArray.last)
myArray.pop
elsif myArray.first > myArray.last
unsortedWords.push(myArray.first)
myArray.delete_at(0)
else myArray.length == 1
sortedWords.push(myArray.first)
myArray.pop # This is my problem area I think???
end # if else
#puts 'sorted words'
#puts sortedWords
#puts 'unsortedWords'
#puts unsortedWords
end # while
puts 'sorted words'
puts sortedWords
puts 'unsortedWords'
puts unsortedWords
myArray = unsortedWords
while myArray.length > 0
sortTheArray myArray
end #while
end # sortTheArray
sortTheArray ArrayofWords
most of those puts's are not necessary, I was just trying to figure out where the problem was.
You've got numerous problems with your code. For example, you seem to want to accumulate sorted words across invocations of this method, but you reinitialize sorted_words to [] at the start of the method block.
I would suggest first trying to express your recursive solution in English as simply as possible and then seek to implement it.
For example, the following is an approach which seems to be in line with what you are trying to do:
def sorted_array(array)
lowest_value prepended to the sorted_value of the array with the lowest_value removed
end
I'm sharing the above because it appears that you're new to Ruby and just implementing the above in an idiomatic fashion will be a good challenge.

Program to take input from command line into an array and find the biggest among them

I am new to Ruby and just can't figure out how you take input for an array from a user and display it.If anyone could clear that I can add my logic to find the biggest number.
#!/usr/bin/ruby
puts "Enter the size of the array"
n = gets.chomp.to_i
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
for i in (0..n)
puts variable1
end
How about capturing the array in one line?
#!/usr/bin/ruby
puts "Enter a list of numbers"
list = gets # Input something like "1 2 3 4" or "3, 5, 6, 1"
max = list.split.map(&:to_i).max
puts "The largest number is: #{max}"
You are doing it ok. But try this little change
#!/usr/bin/ruby
puts "Enter the size of the array"
n = (gets.chomp.to_i - 1)
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
puts variable1
or for undefined number of values here is one way
#!/usr/bin/ruby
puts "enter the array elements (type 'done' to get out)"
input = gets.chomp
arr = []
while input != 'done'
arr << input.to_i
input = gets.chomp
end
puts arr
I believe that this is a little bit more elegant solution.
puts "Please enter numbers separated by spaces:"
s = gets
a = s.split(" ")
#Displays array
puts a
#Displays max element
puts a.max
First you collect the series of numbers from the user, then you use a split method on the string, which converts it to the array. If you want to use some other separator, like "," than you can write s.split(","). After that you can use your logic to find the biggest number or you could just use max method.
Some feedback:
chomp.to_i is a bit redundant, since the latter will also remove newlines.
for x in y is not commonly seen in idiomatic Ruby code. It basically behaves like each with slightly different scoping rules and probably should have been removed from the language a while ago.
Ruby arrays are dynamic, so no need to preinitialize them. Something like (1..n).map { gets.to_i } would also produce the array you need.
Displaying it can then be done like this: array.each { |n| puts n }
Alternatively you can use the strip approach outlined before, take the numbers as command line arguments in ARGV or pipe into your program using ARGF.

Loop returns only the last item

I'm new to Ruby, so the answer is probably pretty simple. Not to me though
I am taking an array of strings (A) and matching it against another array of strings (B) to see if a given string from (A) exists as a substring within a string from B.
The compare seems to work however, I only get back a result from the last (A) string compared.
What might this be?
def checkIfAvailableOnline(film)
puts "Looking for " + film
lowerCaseFilm = film.downcase
#iterate through the linesarray scanning for the film in question
for line in #linesArray
#get the line in lowercase
lowerCaseLine = line.downcase
#look for the film name as a substring within the line
results = lowerCaseLine.scan(lowerCaseFilm)
if results.length > 0
#availableOnlineArray << results
end
end
end
#-----------------------------------------
listFilmsArray.each {|line| checkIfAvailableOnline(line)}
Given a list of film names:
FILM_NAMES = [
'Baked Blue Tomatoes',
'Fried Yellow Tomatoes',
'The thing that ate my homework',
'In a world where',
]
Then to find all film names containing a substring, ignoring case:
def find_films_available_online(partial_film_name)
FILM_NAMES.find_all do |film_name|
film_name.downcase[partial_film_name.downcase]
end
end
p find_films_available_online('tomatoes')
# => ["Baked Blue Tomatoes", "Fried Yellow Tomatoes"]
p find_films_available_online('godzooka')
# => []
To find out if a film name is available online:
def available_online?(partial_film_name)
!find_films_available_online(partial_film_name).empty?
end
p available_online?('potatoes') # => false
p available_online?('A World') # => true
To find out which of a list of partial film names are available online:
def partial_film_names_available_online(partial_film_names)
partial_film_names.find_all do |partial_film_name|
available_online?(partial_film_name)
end
end
p partial_film_names_available_online [
'tomatoes',
'potatoes',
'A World',
]
# => ["tomatoes", "A World"]
A more rubyish way to do this is:
Given an array of films we are looking for:
#films = ["how to train your dragon", "kung fu panda", "avatar"]
Given an array of lines that may contain the films we are looking for:
#lines_array = ["just in kung fu panda", "available soon how to train your dragon"]
Return the film name early if it exists in a line or false if it doesn't after searching all the lines:
def online_available(film)
#lines_array.each do |l|
l.downcase.include?(film) ? (return film) : false
end
false
end
Check for the films in the lines rejecting the ones that returned false, print them and ultimately return an array of the matches we found:
def films_available
available = #films.collect{ |x| p "Looking for: #{x}"; online_available(x) }
.reject{ |x| x == false }
available.each{|x| p "Found: #{x}"}
available
end
It is considered bad style to use camel-case in method names with Ruby but you know what they say about opinions.
.each is an internal iterator and I'm pretty sure the "for" loop will run slower than the enumerable each method that arrays inherit.

Resources