Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am struggling finding a way to verify these methods and was wondering if anyone knew a basic way to do this?
class PigLatinTest < MiniTest::Unit::TestCase
def test_word_beginning_with_a
assert_equal "appleay", PigLatin.translate("apple")
end
def test_other_word_beginning_e
assert_equal "earay", PigLatin.translate("ear")
end
def test_word_beginning_with_p
assert_equal "igpay", PigLatin.translate("pig")
end
For example the first one might be:
module PigLatin
class Word
def initialize(word)
#word = word.to_s
end
# remember to use the .to_s method
def translate(word)
if word[0] == "a" || "e" || "o" || "u" || "i"
word = word + "ay"
elsif word[0] != "a" || "e" || "o" || "u" || "i"
word = word-word[0]+"ay"
end
end
end
# you can add method here even outside of the class ...
end
------------in another file
module PigLatin
class Word
# remember to use the .to_s method
end
# you can add method here even outside of the class ...
end
Your translate method won't work. The problem is here:
if word[0] == "a" || "e" || "o" || "u" || "i"
and
elsif word[0] != "a" || "e" || "o" || "u" || "i"
You can't compare that way as the right side of either will not do what you think it will.
Some simple checks will show why there's something wrong:
'abc'[0] == "a" || "e" || "o" || "u" || "i" # => true
'efg'[0] == "a" || "e" || "o" || "u" || "i" # => "e"
'opq'[0] == "a" || "e" || "o" || "u" || "i" # => "e"
'xyz'[0] == "a" || "e" || "o" || "u" || "i" # => "e"
'abc'[0] != "a" || "e" || "o" || "u" || "i" # => "e"
'efg'[0] != "a" || "e" || "o" || "u" || "i" # => true
'opq'[0] != "a" || "e" || "o" || "u" || "i" # => true
'xyz'[0] != "a" || "e" || "o" || "u" || "i" # => true
Why are those wrong? Let's look at what's happening:
When the word starts with 'a', the test 'a' == 'a' is true:
'abc'[0] == "a" # => true
If we || ("or") true and something, we get true back because it was the first "true" value seen:
true || "e" # => true
If the first test failed, then || causes the second test to be evaluated, which in your code was "e", and wasn't a test, but Ruby didn't know that, and thought it was a "true" return value so it became the result of the expression:
false || "e" # => "e"
Knowing that, a correct way to write this would be:
'abc'[0] == "a" || 'abc'[0] == "e" || 'abc'[0] == "o" || 'abc'[0] == "u" || 'abc'[0] == "i" # => true
'efg'[0] == "a" || 'efg'[0] == "e" || 'efg'[0] == "o" || 'efg'[0] == "u" || 'efg'[0] == "i" # => true
'opq'[0] == "a" || 'opq'[0] == "e" || 'opq'[0] == "o" || 'opq'[0] == "u" || 'opq'[0] == "i" # => true
'xyz'[0] == "a" || 'xyz'[0] == "e" || 'xyz'[0] == "o" || 'xyz'[0] == "u" || 'xyz'[0] == "i" # => false
'abc'[0] != "a" && 'abc'[0] != "e" && 'abc'[0] != "o" && 'abc'[0] != "u" && 'abc'[0] != "i" # => false
'efg'[0] != "a" && 'efg'[0] != "e" && 'efg'[0] != "o" && 'efg'[0] != "u" && 'efg'[0] != "i" # => false
'opq'[0] != "a" && 'opq'[0] != "e" && 'opq'[0] != "o" && 'opq'[0] != "u" && 'opq'[0] != "i" # => false
'xyz'[0] != "a" && 'xyz'[0] != "e" && 'xyz'[0] != "o" && 'xyz'[0] != "u" && 'xyz'[0] != "i" # => true
however, that rapidly becomes hard to read and unwieldy, so something more concise is needed:
%w[a e o u].include? 'abc'[0] # => true
%w[a e o u].include? 'efg'[0] # => true
%w[a e o u].include? 'opq'[0] # => true
%w[a e o u].include? 'xyz'[0] # => false
!%w[a e o u].include? 'abc'[0] # => false
!%w[a e o u].include? 'efg'[0] # => false
!%w[a e o u].include? 'opq'[0] # => false
!%w[a e o u].include? 'xyz'[0] # => true
There is a problem with this though; As the array size increases, more loops are required to compare to the [0] value, which slows the code unnecessarily. A regular expression, written correctly, can get rid of that looping so the speed stays very constant:
'abc'[0][/[aeou]/] # => "a"
'efg'[0][/[aeou]/] # => "e"
'opq'[0][/[aeou]/] # => "o"
'xyz'[0][/[aeou]/] # => nil
Notice though, that instead of getting true/false, the results are the character matched by the pattern or nil. In Ruby, only nil and false are considered false values, and everything else is true, so we can translate those into true, true, true, false respectively, but by taking advantage of the ! operator we can make it even more clear:
!!'abc'[0][/[aeou]/] # => true
!!'efg'[0][/[aeou]/] # => true
!!'opq'[0][/[aeou]/] # => true
!!'xyz'[0][/[aeou]/] # => false
It might seem that we'd have to use !!! to "not" the results like we'd want when using !=, but that isn't necessary. A single ! will do the same thing:
!'abc'[0][/[aeou]/] # => false
!'efg'[0][/[aeou]/] # => false
!'opq'[0][/[aeou]/] # => false
!'xyz'[0][/[aeou]/] # => true
But wait! There's more! Even that can be improved upon a slight amount by removing the string slice ([0]) and using a regex anchor. Compare these two, and their benchmark:
require 'fruity'
ALPHABET = ('a'..'z').to_a.join
compare do
slice_it { ALPHABET[0][/[aeou]/] }
regex_it { ALPHABET[/^[aeou]/] }
end
# >> Running each test 8192 times. Test will take about 1 second.
# >> regex_it is faster than slice_it by 39.99999999999999% ± 10.0%
So, using something like:
'abc'[/^[aeou]/] # => "a"
!'abc'[/^[aeou]/] # => false
!!'abc'[/^[aeou]/] # => true
will be fast and compact and let you test to see what a string starts with.
Related
I only want to do a simple loop:
I want something like:
loop do
puts "What hotel would you like to pick"
hotelCode = gets.chomp.downcase #gets user input and puts it lowerCase
if hotelCode != "a" || hotelCode != "b" || hotelCode != "c" || hotelCode != "d" # if user input is not a,b,c,d break
break
else
puts "How many nights would you like to stay"
nights = gets.chomp.to_i
end
end #end while loop
puts "congrats u got out"
In my code, it just keeps breaking out of the loop no matter what I do. Am I missing something obvious?
Maybe you want your loops ends if the input is NONE of those choice. So
if hotelCode != "a" && hotelCode != "b" & hotelCode != "c" && hotelCode != "d"
better
if !["a", "b", "c", "d"].include?(hotelCode)
even better
if !%w(a b c d).include?(hotelCode)
or
unless %w(a b c d).include?(hotelCode)
From your code, it should be something like this:
loop do
puts "What hotel would you like to pick"
hotelCode = gets.chomp.downcase #gets user input and puts it lowerCase
if hotelCode != "a" && hotelCode != "b" && hotelCode != "c" && hotelCode != "d" # if user input is not a,b,c,d break
break
else
puts "How many nights would you like to stay"
nights = gets.chomp.to_i
end
end #end while loop
puts "congrats u got out"
if hotelCode != "a" || hotelCode != "b" || ...
If hotel code is "b", it will break on the first condition. If it is "a", it will break on the second. This condition is impossible to satisfy.
Either use
if hotelCode != "a" && hotelCode != "b" && ...
or
if hotelCode == "a" || hotelCode == "b" || ...
# handle valid hotel
else
break
end
Simple boolean math :) Or better yet, use one of Ursus' examples.
I would suggest using a method of the String class. Here are several, ordered by my personal preference (high to low).
hotel_code !~ /[abcd]/
hotel_code =~ /[^abcd]/
!"abcd".include?(hotel_code)
"abcd".index(hotel_code).nil?
hotel_code.count("abcd").zero?
hotel_code.delete("abcd") == hodel_code
"abcd".delete(hotel_code) == "abcd"
The second returns an integer ("truthy") or nil ("falsy"); the others return true or false.
I have a hash here:
VALID_CHOICES = {
'r' => 'rock',
'p' => 'paper',
'sc' => 'scissors',
'l' => 'lizard',
'sp' => 'spock'
}
And a method which basically compares here:
def win?(first, second)
(first == 'sc' && second == 'p') ||
(first == 'p' && second == 'r') ||
(first == 'r' && second == 'l') ||
(first == 'l' && second == 'sp') ||
(first == 'sp' && second == 'sc') ||
(first == 'sc' && second == 'l') ||
(first == 'l' && second == 'p') ||
(first == 'p' && second == 'sp') ||
(first == 'sp' && second == 'r') ||
(first == 'r' && second == 'sc')
end
How can I rewrite my method in very short concise code that means exactly the same thing? Any idea? Is it possible to do it using hashes?
You should define clear rules for what each token can win:
WINS = {
'r' => %w{l sc},
'p' => %w{r sp},
'sc' => %w{p l},
'l' => %w{p sp},
'sp' => %w{r sc}
}
Now you can determine wins using a simple lookup:
def win?(first, second)
WINS[first].include?(second)
end
While there may be several 'clever' ways to avoid an explicit structure like WINS, explicit rules are much more understandable - and therefore, more maintainable. Conciseness in code is considered a positive attribute where it improves the readability of the code. Conciseness to the extreme that causes the code to be difficult to understand is not something to strive for.
In addition to user2864740's comment and Cary Swoveland's explanation, you could also use a hash to map "winning pairs" to their respective verb:
WINS = {
%w[scissors paper] => 'cuts',
%w[paper rock] => 'covers',
%w[rock lizard] => 'crushes',
%w[lizard spock] => 'poisons',
%w[spock scissors] => 'smashes',
%w[scissors lizard] => 'decapitates',
%w[lizard paper] => 'eats',
%w[paper spock] => 'disproves',
%w[spock rock] => 'vaporizes',
%w[rock scissors] => 'crushes'
}
It returns the corresponding verb if the key's first item beats the second:
WINS[['paper', 'rock']] #=> "covers"
and nil if it doesn't:
WINS[['rock', 'paper']] #=> nil
In your method:
def win?(first, second)
WINS.has_key?([first, second])
end
Or to check both sides:
if WINS.has_key?([first, second])
# first wins
elsif WINS.has_key?([second, first])
# second wins
else
# tie
end
Or more verbose:
def result(first, second)
if verb = WINS[[first, second]]
"first wins: #{first} #{verb} #{second}"
elsif verb = WINS[[second, first]]
"second wins: #{second} #{verb} #{first}"
else
"tie"
end
end
result('rock', 'scissors')
#=> "first wins: rock crushes scissors"
result('spock', 'lizard')
#=> "second wins: lizard poisons spock"
result('paper', 'paper')
#=> "tie"
Of course, you can also use your abbreviations (sc, p, r, l, sp) instead of whole words.
This question already has answers here:
Test if variable matches any of several strings w/o long if-elsif chain, or case-when
(3 answers)
Closed 6 years ago.
I cannot get my validator to function properly.
I need to allow the user to be able to enter letters A-F (upper and lowercase) while giving them an error if they enter otherwise.
Here is my code:
print "Enter a letter A-E to add to your order "
items=gets.upcase.chomp
if items != ("A" || "B" || "C" || "D" || "E")
puts ("Incorrect Letter")
end
It functions correctly if 'A' or 'a' are entered, but it does not work at all for any of the other numbers. It seems simple enough that it should work.
Any idea what I'm doing wrong here?
if (items != "A" || items != "B" || items != "C" || items != "D" || items != "E")
is a working version with the "||".
unless items.between?("A", "E")
is perhaps more readable.
("A" || "B" || "C" || "D" || "E") is an expression that always evaluates to "A", since "A" is "truthy". Therefore, your if statement is equivalent to if items != 'A'
To check if the input is one of many options, use Array's include? function: http://ruby-doc.org/core-2.2.0/Array.html#method-i-include-3F
if ["A", "B", "C", "D", "E"].include?(items)
("A" || "B" || "C" || "D" || "E") always returns "A" in Ruby, since "A" is a not nil of false:
nil || "B"
#=> "B"
false || "B"
#=> "B"
"A" || false
#=> "A"
"A" || "B"
#=> "A"
"A" || "B" || "C"
#=> "A"
and so on.
You should use include:
unless ["A","B","C","D","E"].include?(items) puts ("Incorrect Letter") end
Since you want to include both lower- and uppercase letters, I suggest this:
unless ("a".."e").include?(items.downcase) puts ("Incorrect Letter")
I'm trying to write code in Ruby that removes all the vowels from a string:
def remvowel(string)
i = 0
dv_string = []
while i < string.length
if (string[i] != "a" || string[i] != "e" || string[i] != "i" || string[i] != "o" || string[i] != "u")
dv_string.push(i)
i += 1
end
i += 1
end
return dv_string.join
end
But it's not coming out right. When I run remvowel("duck"), it returns "02", as in the index positions of "dc". I'm missing something, but I don't know what.
You could just:
string.gsub(/[aeiou]/, '')
Or even better:
string.tr('aeiou', '')
And the best tool for deleting characters in a string is...
string.delete('aeiou')
That's because you're pushing i instead of string[i].
dv_string.push(i)
This is what you want:
dv_string.push(string[i])
However, that's a rather verbose and roundabout way of accomplishing the task. A somewhat more idiomatic Ruby approach would look like any of the ones ndn posted:
def remvowel(string)
string.gsub /[aeiou]/, ''
end
or
def remvowel(string)
string.tr 'aeiou',''
end
or
def remvowel(string)
string.delete 'aeiou'
end
You've got it almost right:
def remvowel(string)
i = 0
dv_string = []
while i < string.length
if (string[i] != "a" || string[i] != "e" || string[i] != "i" || string[i] != "o" || string[i] != "u")
# Push the letter, not i
dv_string.push(string[i])
# Don't increment i here
end
i += 1
end
return dv_string.join
end
Your algorithm increments i twice if you encounter a consonant, so you are skipping every second letter.
Here is one more way this can be done:
s = "Hello, how are you you?"
vowels = "aeiou"
puts (s.chars - vowels.chars).join
#=> Hll, hw r y y?
Thank you everybody for your contributions. Thanks to you all (and especially you, Cary Swoveland), I not only know better ways to do this in the future, but even found an answer for my "scenic route" way of doing it!
def remvowel(string)
i = 0
dv_string = []
while i < string.length
dv_string.push(string[i])
if (string[i] == "a" || string[i] == "e" || string[i] == "i" || string[i] == "o" || string[i] == "u")
dv_string.delete(string[i])
end
i += 1
end
return dv_string.join
end
Granted, I'm gonna be doing the more sensible way from the responses here from now on, but mission accomplished!
I can't make my code pass this test:
it "translates two words" do
s = translate("eat pie")
s.should == "eatay iepay"
end
I don't see the flaw in my logic, though it may be very brute force and there may be a simpler way of passing the test:
def translate(string)
string_array = string.split
string_length = string_array.size
i=0
while i < string_length
word = string_array[i]
if word[0] == ("a" || "e" || "i" || "o" || "u")
word = word + "ay"
string_array[i] = word
elsif word[0] != ( "a" || "e" || "i" || "o" || "u" ) && word[1] != ( "a" || "e" || "i" || "o" || "u" )
word_length = word.length-1
word = word[2..word_length]+word[0]+word[1]+"ay"
string_array[i] = word
elsif word[0] != ( "a" || "e" || "i" || "o" || "u" )
word_length = word.length-1
word = word[1..word_length]+word[0]+"ay"
string_array[i] = word
end
i += 1
end
return string_array.join(" ")
end
Here's the test failure message:
Failures:
1) #translate translates two words
Failure/Error: s.should == "eatay iepay"
expected: "eatay iepay"
got: "ateay epiay" (using ==)
# ./04_pig_latin/pig_latin_spec.rb:41:in `block (2 levels) in <top (required)>'
The additional code checking other conditions are for other tests that I already passed. Basically, now I'm checking a string with two words.
Please let me know how I can make the code pass the test. Thank you in advance!
"a" || "e" || "i" || "o" || "u" is evaluated to "a" because "a" is truth value. (not a nil, not a false):
irb(main):001:0> ("a" || "e" || "i" || "o" || "u")
=> "a"
irb(main):002:0> "a" == ("a" || "e" || "i" || "o" || "u")
=> true
irb(main):003:0> "e" == ("a" || "e" || "i" || "o" || "u")
=> false
How about using Array#include? instead:
irb(main):001:0> %w{a e i o u}.include? "a"
=> true
irb(main):002:0> %w{a e i o u}.include? "e"
=> true
or using =~ (regular expression match):
irb(main):007:0> "e" =~ /[aeiou]/
=> 0