Ruby Spell Checker Not Working Properly - ruby

I am writing a small project in ruby that takes all of the words from a website and then sorts them short to long.
To verify that what gets sorted is actually valid english I am comparing an array of scraped words to the basic unix/osx words file.
The method to do this is the spell_check method. The problem is that when used on small arrays is works fine, but with larger ones it will let non-words through. Any ideas?
def spell_check (words_array)
dictionary = IO.read "./words.txt"
dictionary = dictionary.split
dictionary.map{|x| x.strip }
words_array.each do |word|
if !(dictionary.include? word)
words_array.delete word
end
end
return words_array
end

I simplified your code, maybe this will work?
def spell_check(words)
lines = IO.readlines('./words.txt').map { |line| line.strip }
words.reject { |word| !lines.include? word }
end
I noticed that you were trying to modify the words_array while you were simultaneously iterating over it with each:
words_array.each do |word|
if !(dictionary.include? word)
words_array.delete word # Delete the word from words_array while iterating!
end
end
I'm not sure if this is the case in Ruby, but in other programming languages like Java and C#, trying to modify a collection, while you're iterating over it at the same time, invalidates the iteration, and either produces unexpected behavior, or just throws an error. Maybe this was your problem with your original code?
Also, the return statement was unnecessary in your original code, because the last statement evaluated in a Ruby block is always returned (unless there's an explicit return that precedes the last statement). It's idiomatic Ruby to leave it out in such cases.

Related

Troubleshooting a method challenge with Ruby

Simple question here. I never programmed in ruby... so I thought I asked here to confirm if I'm even close to the solution.
Challenge:
Problem Definition: This Ruby method should ensure that the word "Twitter" is spelt correctly.
def fix_spelling(name)
if name = "twittr"
name = "twitter"
else
fix_spelling(name)
end
return "name"
end
I checked how to build methods in ruby and I came out with the following solution:
The problems I identified:
the method is being called inside the function so it will never print anything.
the return is actually returning a string "name" rather that the variable.
def fix_spelling(name)
if name = "twittr"
name = "twitter"
end
return name
end
puts fix_spelling("twittr")
Would this be correct?
Priting:
def fix_spelling(name)
if name == "twittr"
name = "twitter"
end
return name
end
puts fix_spelling(name = "twittr");
Fixing and Shortening the Original Code
A much shorter and more idiomatic version of your current solution looks like this:
def fix_spelling name
name == 'twittr' ? 'twitter' : name
end
# validate inputs
p %w[twitter twittr twit].map { |word| fix_spelling word }
#=> ["twitter", "twitter", "twit"]
However, this essentially just returns name for any other value than twittr, whether it's spelled correctly or not. If that's what you expect, fine. Otherwise, you'll need to develop a set of case statements or return values that can "correct" all sorts of other misspellings. You might also consider using the Levenshtein distance or other heuristic for fuzzy matching rather than using fixed strings or regular expressions to map your inputs to outputs.
Fuzzy Matching
Consider this alternative approach, which uses a gem to determine if the Damerau-Levenshtein edit distance is ~50% of the length of your correctly-spelled word, allows for additional words, and returns the original word bracketed by question marks when it can't be corrected:
require 'damerau-levenshtein'
WORD_LIST = %w[Facebook Twitter]
def autocorrect word
WORD_LIST.map do |w|
max_dist = (w.length / 2).round
return w if DamerauLevenshtein.distance(w, word) <= max_dist
end
'?%s?' % word
end
# validate inputs
p %w[twitter twittr twit facebk].map { |word| autocorrect word }
#=> ["Twitter", "Twitter", "?twit?", "Facebook"]
This isn't really a "spellchecker in a box," but provides a foundation for a more flexible framework if that's where you're going with this. There are a lot of edge cases such as correct-word mapping, capitalization, word stemming, and abbreviations (think "fb" for Facebook) that I'm excluding from the scope of this answer, but edit distance will certainly get you further along towards a comprehensive auto-correct solution than the original example would. Your mileage may certainly vary.

Both for & each loops stop after first match when iterating through a hash in ruby

I'm trying to print out the values of a hash where their corresponding keys match a certain condition (if they're odd).
I'm having an issue that's causing my loop to stop working after
The following code returns only the first matching value.
if mycondition
for key,value in myhash do
if key.odd?
return "#{value}"
end
end
end
After reading some other questions, I thought return was my issue, but when I take it out, the code returns the entire hash instead of just one matching value.
Anyone know what might be up?
This is a much more Ruby way of doing it:
myhash.select do |key, value|
key.odd?
end.values
Here it finds all the odd keys and returns the associated values.
The problem with your return is that forces the whole method to exit right then and there. If you're used to JavaScript that might be a little confusing, as you're not just exiting the do block.
As a note the for construct is hardly ever used in Ruby. A more conventional way of expressing your original code is:
myhash.each do |key, value|
# ...
end
Once you return, the function is over, so that's why you get only one key.
If you don't return anything, the function returns its final expression, which in this case is the for loop. for loops evaluate to the thing you looped over (myhash), so that's why removing the return gives you everything.
In your case you need to build up the list of things you want to return, and that return that whole list:
if mycondition
ret = []
for key, value in myhash do
if key.odd?
ret << [key, value]
end
end
return Hash[ret]
end
But Ruby has much nicer ways to pull out a subset of a hash, for example:
Hash[myhash.select{|k,v| k.odd?}]

Ruby Anagram Comparison Module

I am new to Ruby and trying to figure out a problem for an online test. The problem is as follows:
An anagram is a word formed from another by rearranging its letters,
using all the original letters exactly once; for example, orchestra
can be rearranged into carthorse.
Write a function that checks if two words are each other's anagrams.
For example, AreAnagrams.are_anagrams?('momdad', 'dadmom') should
return true as arguments are anagrams.
The code I have come up with is this:
module AreAnagrams
def self.are_anagrams?(string_a, string_b)
## Create #word1 variable to store string_a
#word1 = string_a
## Create #word1_compare variable to store string_a in lower case
#word1_compare = #word1.downcase
## Create #word2_compare variable to store string_b
#word2 = string_b
## Create #word2_compare variable to store string_b in lower case
#word2_compare = #word2.downcase
## Check length of #word1 and #word2 to make sure they are the same length
if #word1.length == #word2.length
=begin
Sort the letters of the #word1 and #word2 variables and compare
them to see if they are anagrams
=end
if #word1_compare.chars.sort.join == #word2_compare.chars.sort.join
puts "#{#word1} and #{#word2} are anagrams!"
else
puts "#{#word1} and #{#word2} are not anagrams!"
end
else
puts "#{#word1} and #{#word2} are not anagrams!"
end
end
end
When I submit the code, I get the following back from the test:
Compilation OK, but 4 out of 4 test cases fail
Sample case: Wrong answer
Words with unique letters: Wrong answer
Words with duplicate letters: Wrong answer
One word is the prefix of another word: Wrong answer
I have tested my code with multiple strings and it seems to work just fine. It looks like it wants me to check for more specific instances (special characters, words with duplicate letters, etc.) but is that really required? Sorry if it's a dumb question, I'm new to Ruby and lost.
Any help would be greatly appreciated!
I think the problem here is you're displaying a message but not returning a true or false value which is what is expected.
After each puts, include the appropriate answer. That way your method will return something useful. Right now I'm presuming it's nil for all cases, since that's what puts returns.

Push an array into another array with Ruby, and return square brackets

I've spent a few hours searching for a way to push an array into another array or into a hash. Apologies in advance if the formatting of this question is bit messy. This is the first time I've asked a question on StackOverflow so I'm trying to get the hang of styling my questions properly.
I have to write some code to make the following test unit past:
class TestNAME < Test::Unit::TestCase
def test_directions()
assert_equal(Lexicon.scan("north"), [['direction', 'north']])
result = Lexicon.scan("north south east")
assert_equal(result, [['direction', 'north'],
['direction', 'south'],
['direction', 'east']])
end
end
The most simple thing I've come up with is below. The first part passes, but then the second part is not returning the expected result when I run rake test.
Instead or returning:
[["direction", "north"], ["direction", "south"], ["direction",
"east"]]
it's returning:
["north", "south", "east"]
Although, if I print the result of y as a string to the console, I get 3 separate arrays that are not contained within another array (as below). Why hasn't it printed the outermost square brackets of the array, y?
["direction", "north"]
["direction", "south"]
["direction", "east"]
Below is the code I've written in an attempt to pass the test unit above:
class Lexicon
def initialize(stuff)
#words = stuff.split
end
def self.scan(word)
if word.include?(' ')
broken_words = word.split
broken_words.each do |word|
x = ['direction']
x.push(word)
y = []
y.push(x)
end
else
return [['direction', word]]
end
end
end
Any feedback about this will be much appreciated. Thank you all so much in advance.
What you're seeing is the result of each, which returns the thing being iterated over, or in this case, broken_words. What you want is collect which returns the transformed values. Notice in your original, y is never used, it's just thrown out after being composed.
Here's a fixed up version:
class Lexicon
def initialize(stuff)
#words = stuff.split
end
def self.scan(word)
broken_words = word.split(/\s+/)
broken_words.collect do |word|
[ 'direction', word ]
end
end
end
It's worth noting a few things were changed here:
Splitting on an arbitrary number of spaces rather than one.
Simplifying to a single case instead of two.
Eliminating the redundant return statement.
One thing you might consider is using a data structure like { direction: word } instead. That makes referencing values a lot easier since you'd do entry[:direction] avoiding the ambiguous entry[1].
If you're not instantiating Lexicon objects, you can use a Module which may make it more clear that you're not instantiating objects.
Also, there is no need to use an extra variable (i.e. broken_words), and I prefer the { } block syntax over the do..end syntax for functional blocks vs. iterative blocks.
module Lexicon
def self.scan str
str.split.map {|word| [ 'direction', word ] }
end
end
UPDATE: based on Cary's comment (I assume he meant split when he said scan), I've removed the superfluous argument to split.

repl.it Ruby interpreter : error when defining multiple functions containing loops

I'm relatively new to programming and even newer to Ruby, and I've been using the repl.it Ruby interpreter to test code. However, I've run into the same problem multiple times now whenever I try to enter in multiple function definitions that contain loops -- I inevitably get an error message that looks like this:
(eval):350: (eval):350: compile error (SyntaxError)
(eval):344: syntax error, unexpected kDO_COND, expecting kEND
(eval):350: syntax error, unexpected kEND, expecting $end
Does anyone know what the problem is and how to avoid this? It doesn't look like a code error per se, since my code seems to run fine with codepad. But I've been told to use this specific interpreter to test code for a program I'm applying to.
Here's my code (I'm testing two different methods I wrote to reverse a string, one in place and the other using a new output list):
def reverse(s)
#start by breaking the string into words
words = s.split
#initialize an output list
reversed = []
# make a loop that executes until there are no more words to reverse
until words.empty?
reversed << words.pop.reverse
end
# return a string of the reversed words joined by spaces
return reversed = reversed.join(' ')
end
def reverse_string(s)
# create an array of words and get the length of that array
words = s.split
count = words.count #note - must be .length for codepad's older Ruby version
#For each word, pop it from the end and insert the reversed version at the beginning
count.times do
reverse_word = words.pop.reverse
words.unshift(reverse_word)
end
#flip the resulting word list and convert it to a string
return words.reverse.join(' ')
end
a = "This is an example string"
puts reverse(a)
puts reverse_string(a)
Your code is fine; their interpreter is old. If you change the block syntax that you use with times, e.g.
count.times {
reverse_word = words.pop.reverse
words.unshift(reverse_word)
}
...suddenly it works.

Resources