This is almost certainly a duplicate, but I can't find the original - I don't know the search terms to use. Which is why I'm on Stackoverflow instead of Google :)
Anyhow, here's my code:
def titleize(say)
index = 0
words = say.split
words.each do |word|
unless word == "and" || "or" || "over" || "the" || "for"
word.capitalize!
end
if index == 0
word.capitalize!
end
index += 1
end
say = words.join(" ")
end
Because index is declared before the loop, my if index == 0 is not working.
How do I let Ruby know about and use my object index? Also: what is this called?
Using index == 0 is perfectly fine as index is accessible within your loop. Your real problem is probably in this line:
word == "and" || "or" || "over" || "the" || "for"
This is always true-like! What you mean is:
["and", "or", "over", "the", "for"].include? word
Apart form that there is a method called each_with_index, which you can use like this:
words.each_with_index do |word, index|
I think you want to use with_index. Your word comparison was busted too.
def titleize(say)
words = say.split
l = ["and", "or", "over", "the", "for"]
words.each.with_index do |word, index|
word.capitalize! if index == 0 || !(l.include? word)
end
say = words.join(" ")
end
puts(titleize("hello there for you"))
puts(titleize("hi"))
puts(titleize("for"))
That's not how booleans work. The way this is evaluated is:
x == 'a' || 'b'
Becomes:
(x == 'a') || 'b'
Which is equivalent to:
'b'
What you're intending, translated to more idiomatic Ruby, is:
def titleize(say)
say.split.each_with_index do |word, index|
if (index == 0)
word.capitalize!
else
case (word)
when "a", "and", "or", "over", "the", "for"
# Leave lower-case
else
word.capitalize!
end
end
end.join(' ')
end
titleize('the time this is a test for the things!')
# => "The Time This Is a Test for the Things!"
I would do this it is more flexible and more ruby-esque
def titleize(sentence,exclusions=[])
sentence.split.map.with_index do |word,index|
(index == 0 || !exclusions.include?(word)) ? word.capitalize : word
end.join(' ')
end
For this case i used 'capitalize' without the bang in case any of the words are already capitalized.
"Hello".capitalize! #=> nil
"Hello".capitalize #=> "Hello"
It will also let you re-use the same list of exclusion or change them as you see fit
Call as
exclude = ["and", "or", "over", "the", "for"]
titleize("hello there you are over there", exclude)
#=> "Hello There You Are over There"
Your code returns the modification of say, but does change the contents of the variable. It appears that you want to modify the argument, but I'm not sure about that. I will first suggest a way to return the modified value of say (but not alter the value of say, and then will show how you could change the code to modify the argument.
Notice that I do not employ an index, and use a case statement to determine whether words after the first should be capitalized.
Code
def titleize(say)
words = say.split
return "" if words.empty?
words.first.capitalize!
return words.first if words.size == 1
words[1..-1].each do |word|
case word
when "and", "or", "over", "the", "for"
else
word.capitalize!
end
end
words.join(' ')
end
Examples
say = "and now is the time for all Rubyists to hunker down and code"
titleize(say)
#=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say
#=> "and now is the time for all Rubyists to hunker down and code"
say = " "
titleize(say)
#=> ""
say = " and "
titleize(say)
#=> "And"
Modifying the Argument
If you wish to modify the argument say, use String#replace:
def titleize_and_modify_arg(say)
words = say.split
str =
case words.size
when 0
""
when 1
words.first.capitalize
else
words.first.capitalize!
words[1..-1].each do |word|
case word
when "and", "or", "over", "the", "for"
else
word.capitalize!
end
end
words.join(' ')
end
say.replace(str)
end
say = "and now is the time for all Rubyists to hunker down and code"
titleize_and_modify_arg(say)
#=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say
#=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say = " and "
titleize_and_modify_arg(say)
#=> nil
say
#=> " and "
Notice that in the second example, titleize_and_modify_arg modifies say correctly, but returns nil. Of course, the method could be easily changed to return the value of say, as well as changing it, if that were desired.
Note also that, in the case statement, when words.siz => 1, it's capitalize, not capitalize!, as the latter would return nil if the word is already capitalized. capitalize! is need for the else case, however.
I recommend using each_index instead of each. See here.
Try this:
def titleize (say)
words = say.split
words.each_index do |index|
word = words[i]
unless word == "and" || "or" || "over" || "the" || "for"
word.capitalize!
end
if index == 0
word.capitalize!
end
end
say = words.join(" ")
end
Related
I recently solved this problem, but felt there is a simpler way to do it. I looked into inject, step, and map, but couldn't figure out how to implement them into this code. I want to use fewer lines of code than I am now. I'm new to ruby so if the answer is simple I'd love to add it to my toolbag. Thank you in advance.
goal: accept a sentence string as an arg, and return the sentence with words alternating between uppercase and lowercase
def alternating_case(str)
newstr = []
words = str.split
words.each.with_index do |word, i|
if i.even?
newstr << word.upcase
else
newstr << word.downcase
end
end
newstr.join(" ")
end
You could reduce the number of lines in the each_with_index block by using a ternary conditional (true/false ? value_if_true : value_if_false):
words.each.with_index do |word, i|
newstr << i.even? ? word.upcase : word.downcase
end
As for a different way altogether, you could iterate over the initial string, letter-by-letter, and then change the method when you hit a space:
def alternating_case(str)
#downcase = true
new_str = str.map { |letter| set_case(letter)}
end
def set_case(letter)
#downcase != #downcase if letter == ' '
return #downcase ? letter.downcase : letter.upcase
end
We can achieve this by using ruby's Array#cycle.
Array#cycle returns an Enumerator object which calls block for each element of enum repeatedly n times or forever if none or nil is given.
cycle_enum = [:upcase, :downcase].cycle
#=> #<Enumerator: [:upcase, :downcase]:cycle>
5.times.map { cycle_enum.next }
#=> [:upcase, :downcase, :upcase, :downcase, :upcase]
Now, using the above we can write it as following:
word = "dummyword"
cycle_enum = [:upcase, :downcase].cycle
word.chars.map { |c| c.public_send(cycle_enum.next) }.join("")
#=> "DuMmYwOrD"
Note: If you are new to ruby, you may not be familiar with public_send or Enumberable module. You can use the following references.
Enumberable#cycle
#send & #public_send
I am currently developing a small modified version of Hangman in Rails for children. The game starts by randomly generating a word from a text file and the user has to guess the word by entering a four letter word. Each word is the split by each character for example "r", "e", "a", "l" and returns a message on how they are to the word.
Random Generated word is "real"
Input
rlax
Output
Correct, Close, Correct, Incorrect
I have tried other things which I have found online but haven't worked and I am fairly new to Ruby and Rails. Hopefully someone can guide me in the right direction.
Here is some code
def letterCheck(lookAtLetter)
lookAHead = lookAtLetter =~ /[[:alpha:]]/
end
def displayWord
$ranWordBool.each_index do |i|
if($ranWordBool[i])
print $ranWordArray[i]
$isWin += 1
else
print "_"
end
end
end
def gameLoop
turns = 10
turnsLeft = 0
lettersUsed = []
while(turnsLeft < turns)
$isWin = 0
displayWord
if($isWin == $ranWordBool.length)
system "cls"
puts "1: Quit"
puts "The word is #{$ranWord} and You Win"
puts "Press any key to continue"
return
end
print "\n" + "Words Used: "
lettersUsed.each_index do |looper|
print " #{lettersUsed[looper]} "
end
puts "\n" + "Turns left: #{turns - turnsLeft}"
puts "Enter a word"
input = gets.chomp
system "cls"
if(input.length != 4)
puts "Please enter 4 lettered word"
elsif(letterCheck(input))
if(lettersUsed.include?(input))
puts "#{input} already choosen"
elsif($ranWordArray.include?(input))
puts "Close"
$ranWordArray.each_index do |i|
if(input == $ranWordArray[i])
$ranWordBool[i] = true
end
if($ranWordBool[i] = true)
puts "Correct"
else
puts "Incorrect"
end
end
else
lettersUsed << input
turnsLeft += 1
end
else
puts "Not a letter"
end
end
puts "You lose"
puts "The word was #{$ranWord}"
puts "Press any key to continue"
end
words = []
File.foreach('words.txt') do |line|
words << line.chomp
end
while(true)
$ranWord = words[rand(words.length) + 1]
$ranWordArray = $ranWord.chars
$ranWordBool = []
$ranWordArray.each_index do |i|
$ranWordBool[i] = false
end
system "cls"
gameLoop
input = gets.chomp
shouldQuit(input)
end
Something like that:
# Picking random word to guess
word = ['open', 'real', 'hang', 'mice'].sample
loop do
puts "So, guess the word:"
input_word = gets.strip
if word == input_word
puts("You are right, the word is: #{input_word}")
break
end
puts "You typed: #{input_word}"
# Split both the word to guess and the suggested word into array of letters
word_in_letters = word.split('')
input_in_letters = input_word.split('')
result = []
# Iterate over each letter in the word to guess
word_in_letters.each_with_index do |letter, index|
# Pick the corresponding letter in the entered word
letter_from_input = input_in_letters[index]
if letter == letter_from_input
result << "#{letter_from_input} - Correct"
next
end
# Take nearby letters by nearby indexes
# `reject` is here to skip negative indexes
# ie: letter 'i' in a word "mice"
# this will return 'm' and 'c'
# ie: letter 'm' in a word "mice"
# this will return 'i'
letters_around =
[index - 1, index + 1]
.reject { |i| i < 0 }
.map { |i| word_in_letters[i] }
if letters_around.include?(letter_from_input)
result << "#{letter_from_input} - Close"
next
end
result << "#{letter_from_input} - Incorrect"
end
puts result.join("\n")
end
Currently I have a regular expression for zip-codes for the U.S.:
validates :zip,
presence: true,
format: { with: /\A\d{5}(-\d{4})?\z/ }
I want to use different regular expressions for other countries on the same zip-code so the regular expression should be used according to the country:
For Australia 4 digits
For Canada 6 digits alphanumeric
For UK 6-7 digits alphanumeric
Can someone suggest how can I full fill my requirement?
You can give a lambda that returns a Regexp as the :with option for the format validator (see :with), which makes this nice and clean:
ZIP_COUNTRY_FORMATS = {
'US' => /\A\d{5}(-\d{4})?\z/,
'Australia' => /\A\d{4}\z/,
# ...
}
validates :zip, presence: true,
format: { with: ->(record){ ZIP_COUNTRY_FORMATS.fetch(record.country) } }
Note that uses Hash#fetch instead of Hash#[] so that if a country that doesn't exist is given it will raise a KeyError just as a sanity check. Alternatively you could return a default Regexp that matches anything:
ZIP_COUNTRY_FORMATS.fetch(record.country, //)
...or nothing:
ZIP_COUNTRY_FORMATS.fetch(record.country, /.\A/)
...depending on the behavior you want.
You would want to write a method to help you:
validates :zip, presence: true, with: :zip_validator
def zip_validator
case country
when 'AU'
# some regex or fail
when 'CA'
# some other regex or fail
when 'UK'
# some other regex or fail
else
# should this fail?
end
end
Suppose we give examples of valid postal codes for each country in a hash such as the following.
example_pcs = {
US: ["", "98230", "98230-1346"],
CAN: ["*", "V8V 3A2"],
OZ: ["!*", "NSW 1130", "ACT 0255", "VIC 3794", "QLD 4000", "SA 5664",
"WA 6500", "TAS 7430", "NT 0874"]
}
where the first element of each array is a string of codes that will be explained later.
We can construct a regex for each country from this information. (The information would undoubtedly be different in a real application, but I am just presenting the general idea.) For each country we construct a regex for each example postal code, using in part the above-mentioned codes. We then take the union of those regexes to obtain a single regex for that country. Here's one way the regex for an example postal code might be constructed.
def make_regex(str, codes='')
rstr = str.each_char.chunk do |c|
case c
when /\d/ then :DIGIT
when /[[:alpha:]]/ then :ALPHA
when /\s/ then :WHITE
else :OTHER
end
end.
map do |type, arr|
case type
when :ALPHA
if codes.include?('!')
arr
elsif arr.size == 1
"[[:alpha:]]"
else "[[:alpha:]]\{#{arr.size}\}"
end
when :DIGIT
(arr.size == 1) ? "\\d" : "\\d\{#{arr.size}\}"
when :WHITE
case codes
when /\*/ then "\\s*"
when /\+/ then "\\s+"
else (arr.size == 1) ? "\\s" : "\\s\{#{arr.size}\}"
end
when :OTHER
arr
end
end.
join
Regexp.new("\\A" << rstr << "\\z")
end
I've made the regex case-insensitive for letters, but that could of course be changed. Also, for some countries, the regex produced may have to be tweaked manually and/or some pre- or post-processing of postal code strings may be called for. For example, some combinations may have the correct format but nonetheless are not valid postal codes. In Australia, for example, the four digits following each region code must fall within specified ranges that vary by region.
Here are some examples.
make_regex("12345")
#=> /\A\d{5}\z/
make_regex("12345-1234")
#=> /\A\d{5}-\d{4}\z/
Regexp.union(make_regex("12345"), make_regex("12345-1234"))
#=> /(?-mix:\A\d{5}\z)|(?-mix:\A\d{5}-\d{4}\z)/
make_regex("V8V 3A2", "*")
#=> /\A[[:alpha:]]\d[[:alpha:]]\s*\d[[:alpha:]]\d\z/
make_regex("NSW 1130", "!*")
# => /\ANSW\s*\d{4}\z/
Then, for each country, we take the union of the regexes for each example postal code, saving those results as values in a hash whose keys are country codes.
h = example_pcs.each_with_object({}) { |(country, (codes, *examples)), h|
h[country] = Regexp.union(examples.map { |s| make_regex(s, codes) }.uniq) }
#=> {:US=>/(?-mix:\A\d{5}\z)|(?-mix:\A\d{5}-\d{4}\z)/,
# :CAN=>/\A[[:alpha:]]\d[[:alpha:]]\s*\d[[:alpha:]]\d\z/,
# :OZ=>/(?-mix:\ANSW\s*\d{4}\z)|(?-mix:\AACT\s*\d{4}\z)|(?-mix:\AVIC\s*\d{4}\z)|(?-mix:\AQLD\s*\d{4}\z)|(?-mix:\ASA\s*\d{4}\z)|(?-mix:\AWA\s*\d{4}\z)|(?-mix:\ATAS\s*\d{4}\z)|(?-mix:\ANT\s*\d{4}\z)/}
"12345" =~ h[:US]
#=> 0
"12345-1234" =~ h[:US]
#=> 0
"1234" =~ h[:US]
#=> nil
"12345 1234" =~ h[:US]
#=> nil
"V8V 3A2" =~ h[:CAN]
#=> 0
"V8V 3A2" =~ h[:CAN]
#=> 0
"V8v3a2" =~ h[:CAN]
#=> 0
"3A2 V8V" =~ h[:CAN]
#=> nil
"NSW 1132" =~ h[:OZ]
#=> 0
"NSW 1132" =~ h[:OZ]
#=> 0
"NSW1132" =~ h[:OZ]
#=> 0
"NSW113" =~ h[:OZ]
#=> nil
"QLD" =~ h[:OZ]
#=> nil
"CAT 1132" =~ h[:OZ]
#=> nil
The steps performed in make_regex for
str = "V8V 3A2"
codes = "*+"
are as follows.
e = str.each_char.chunk do |c|
case c
when /\d/ then :DIGIT
when /[[:alpha:]]/ then :ALPHA
when /\s/ then :WHITE
else :OTHER
end
end
#=> #<Enumerator: #<Enumerator::Generator:0x007f9ff201a330>:each>
We can see the values that will be generated by this enumerator by converting it to an array.
e.to_a
#=> [[:ALPHA, ["V"]], [:DIGIT, ["8"]], [:ALPHA, ["V"]], [:WHITE, [" "]],
# [:DIGIT, ["3"]], [:ALPHA, ["A"]], [:DIGIT, ["2"]]]
Continuing,
a = e.map do |type, arr|
case type
when :ALPHA
if codes.include?('!')
arr
elsif arr.size == 1
"[[:alpha:]]"
else "[[:alpha:]]\{#{arr.size}\}"
end
when :DIGIT
(arr.size == 1) ? "\\d" : "\\d\{#{arr.size}\}"
when :WHITE
case codes
when /\*/ then "\\s*"
when /\+/ then "\\s+"
else (arr.size == 1) ? "\\s" : "\\s\{#{arr.size}\}"
end
when :OTHER
arr
end
end
#=> ["[[:alpha:]]", "\\d", "[[:alpha:]]", "\\s*", "\\d", "[[:alpha:]]", "\\d"]
rstr = a.join
#=> "[[:alpha:]]\\d[[:alpha:]]\\s*\\d[[:alpha:]]\\d"
t = "\\A" << rstr << "\\z"
#=> "\\A[[:alpha:]]\\d[[:alpha:]]\\s*\\d[[:alpha:]]\\d\\z"
puts t
#=> \A[[:alpha:]]\d[[:alpha:]]\s*\d[[:alpha:]]\d\z
Regexp.new(t)
#=> /\A[[:alpha:]]\d[[:alpha:]]\s*\d[[:alpha:]]\d\z/
I have an unsorted list of area postcodes as follows:
["E1", "E1C", "E1D", "E10", "E11", "E12", "E2", "E3", "E4", "EC1", "EC1A", "EC1M", "EC1N",
"EC1R", "EC1V", "EC1Y", "EC2", "EC2A", "EC2M", "EC2N", "N1", "N10", "N11", "N12",
"N13", "N2", "NW1", "NW10", "NW2" etc]
I'd like to sort them as follows:
["E1", "E1C", "E1D", "E2", "E3", "E4", "E10", "E11", "E12", "EC1", "EC1A", "EC1M", "EC1N",
"EC1R", "EC1V", "EC1Y", "EC2", "EC2A", "EC2M", "EC2N", "N1", "N2", "N10", "N11", "N12",
"N13", "NW1", "NW2, "NW10" etc]
So to sum up the order of the formats for postcodes beginning with E would be:
E1
E1C
E11
EC1
EC1V
Same order for postcodes beginning with N, etc.
What would be the recommended way of sorting such strings? In this case the format of the string is always known, i.e. it will always be 2-4 alphanumberic characters, the first always being a letter.
Should I order the strings by length first and then order within each length group, or is there a more elegant method?
I'd use
array.sort_by do |str|
/\A(\w)(\d+)\Z/ === str
[$1, $2.to_i]
end
or, if you have arbitrary sequences of alternating letters and digits,
array.sort_by do |str|
/\A(\D*)(\d*)(\D*)(\d*)\Z/.match(str)[1..-1].reject(&:blank?).collect do |item|
/\d/ === item ? item.to_i : item
end
end
Kind of a weird way of doing it, but I think this should work:
array.sort do |a, b|
a = a.dup
b = b.dup
regex = /(\d+)/
a.match(regex)
a_num = $1.to_i
b.match(regex)
b_num = $1.to_i
if a_num > b_num
a.gsub!(regex, "1")
b.gsub!(regex, "0")
elsif a_num < b_num
a.gsub!(regex, "0")
b.gsub!(regex, "1")
end
a <=> b
end
I wanted to check if a string is palindrome or not using ruby code.
I am a starter in ruby so not too aquainted with the string methods in ruby
If you are not acquainted with Ruby's String methods, you should have a look at the documentation, it's very good. Mithun's answer already showed you the basic principle, but since you are new to Ruby, there's a couple more things to keep in mind:
*) If you have a predicate method, it's customary to name it with a trailing question mark, e.g. palindrome?.
*) Boolean expressions evaluate to a boolean, so you don't need to explicitly return true or false. Hence a short idiomatic version would be
def palindrome?(str)
str == str.reverse
end
*) Since Ruby's classes are open, you could add this to the string class:
class String
def palindrome?
self == self.reverse
end
end
*) If you don't want to monkey-patch String, you can directly define the method on single object (or use a module and Object#extend):
foo = "racecar"
def foo.palindrome?
self == self.reverse
end
*) You might want to make the palindrome check a bit more complex, e.g. when it comes to case or whitespace, so you are also able to detect palindromic sentences, capitalized words like "Racecar" etc.
pal = "Never a foot too far, even."
class String
def palindrome?
letters = self.downcase.scan(/\w/)
letters == letters.reverse
end
end
pal.palindrome? #=> true
def check_palindromic(variable)
if variable.reverse == variable #Check if string same when reversed
puts "#{ variable } is a palindrome."
else # If string is not the same when reversed
puts "#{ variable } is not a palindrome."
end
end
The recursive solution shows how strings can be indexed in Ruby:
def palindrome?(string)
if string.length == 1 || string.length == 0
true
else
if string[0] == string[-1]
palindrome?(string[1..-2])
else
false
end
end
end
If reading the Ruby string documentation is too boring for you, try playing around with the Ruby practice questions on CodeQuizzes and you will pick up most of the important methods.
def is_palindrome(value)
value.downcase!
# Reverse the string
reversed = ""
count = value.length
while count > 0
count -= 1
reversed += value[count]
end
# Instead of writing codes for reverse string
# we can also use reverse ruby method
# something like this value == value.reverse
if value == reversed
return "#{value} is a palindrom"
else
return "#{value} is not a palindrom"
end
end
puts "Enter a Word"
a = gets.chomp
p is_palindrome(a)
class String
def palindrome?
self.downcase == self.reverse.downcase
end
end
puts "racecar".palindrome? # true
puts "Racecar".palindrome? # true
puts "mississippi".palindrome? # false
str= gets.chomp
str_rev=""
n=1
while str.length >=n
str_rev+=str[-n]
n+=1
end
if str_rev==str
puts "YES"
else
puts "NO"
end
> first method
a= "malayalam"
if a == a.reverse
puts "a is true"
else
puts "false"
end
> second one
a= "malayalam"
a=a.split("")
i=0
ans=[]
a.count.times do
i=i+1
k=a[-(i)]
ans << k
end
if a== ans
puts "true"
else
puts "false"
end
def palindrome?(string)
string[0] == string[-1] && (string.length <= 2 || palindrome?(string[1..-2]))
end
**Solution 1** Time complexity = O(n), Space complexity = O(n)
This solution does not use the reverse method of the String class. It uses a stack(we could use an array that only allows entry and exit of elements from one end to mimic a stack).
def is_palindrome(str)
stack = []
reversed_str = ''
str.each_char do |char|
stack << char
end
until stack.empty?
reversed_str += stack.pop
end
if reversed_str == str
return true
else
return false
end
end
` Solution 2: Time complexity = O(n), Space complexity = O(1)
def inplace_reversal!(str)
i =0
j = str.length - 1
while i < j
temp = str[i]
str[i] = str[j]
str[j] = temp
i+=1
j-=1
end
return str
end
def palindrome?(str)
return "Please pass the string" if str.nil?
str = str.downcase
str_array = str.split('')
reverse_string = str_array.each_index{ |index| str_array[str_array.count - index - 1 ] end
return ("String #{str} is not a palindrome") unless str == reverse_string.join('')
"String #{str} is palindrome"
end