Recursive string modification in Ruby [closed] - ruby

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a string. I need to make every other line reversed. If count is 2, it should display:
"Hola mi amigo \nogima im aloH"
If count is 3, it should display:
"Hola mi amigo \nogima im aloH \nHola mi amigo"
and so on. What is the shortest way to perform string modification between every other "\n"?
My hunch is to use regex. In addition to regex solution, is there any non-regex solution? I would like to see both for comparison.
def hola(count)
if COUNT IS LESS THAN 2
return false
elsif ODD
(("Hola mi amigo ")*((count-1)/2) + "\n") * count
elsif EVEN
(("Hola mi amigo ")*(count/2) + "\n") * count
end
end

If there are no restrictions in the implementation, then try something like this:
string = "Hola mi amigo"
reversed_string = string.reverse
count.times.map { |i| i.odd? ? reversed_string : string }.join "\n"
times.map will create an enumerator. The next block will check if the current index is odd or even; in the first case, it will reverse the string, and return it. Finally, all strings are concatenated together with join (with newlines).
Also, here is another (and probably less efficient) recursive solution:
def hola(count)
if count == 0
''
elsif count.even?
"Hola mi amigo".reverse + "\n" + hola(count - 1)
else
"Hola mi amigo" + "\n" + hola(count - 1)
end
end

Solution 1
I'm surprised no one else has proposed a solution with Enumerable#cycle (perhaps #CarySwoveland is on vacation):
def hola(str, count)
[ str, str.reverse ].cycle.take(count).join("\n")
end
puts hola("Hola mi amigo", 1)
# => Hola mi amigo
puts hola("Hola mi amigo", 2)
# => Hola mi amigo
# ogima im aloH
puts hola("Hola mi amigo", 3)
# => Hola mi amigo
# ogima im aloH
# Hola mi amigo
puts hola("Hola mi amigo", 8)
# => Hola mi amigo
# ogima im aloH
# Hola mi amigo
# ogima im aloH
# Hola mi amigo
# ogima im aloH
# Hola mi amigo
# ogima im aloH
Solution 2
It occurred to me that perhaps OP was actually looking for a recursive solution, as they wrote in the title:
def hola(str, count)
return "" if count <= 0
str + "\n" + hola(str.reverse, count - 1).chomp
end
Output is the same as above. Obviously it's not as efficient, but otherwise I rather like it.

def alternate(str, count)
(("%s\n%s\n" % [str, str.reverse])*(count/2) << str*(count % 2)).chomp
end
str = "Hola mi amigo"
puts alternate(str, 4)
Hola mi amigo
ogima im aloH
Hola mi amigo
ogima im aloH
puts alternate(str, 5)
Hola mi amigo
ogima im aloH
Hola mi amigo
ogima im aloH
Hola mi amigo

Just out of curiosity:
str = '¡Hola mi amigo!'
([str, str.reverse] * (count / 2 + 1)).take(count).join $/
([str] * count).map.with_index { |s, i| i.even? ? s : s.reverse }.join $/
([str] * count).each.with_index.with_object("") do |(s, i), acc|
acc << (i.even? ? s : s.reverse) << $/
end.strip
To make it more robust (credits to Cary,) one might prepare reversed string in advance.

I'm not experienced with Ruby in particular, but from some light searching, I'd use the .reverse method and for-loops inside your elsif statements. It shouldn't be too hard to put together.
A bit of .reverse documentation can be found here:
http://www.informit.com/articles/article.aspx?p=2314083&seqNum=29

Related

Pig Latin converter

I'm currently working on an exercise which involves converting the sentence "The quick brown fox" to “Hetay uickqay rownbay oxfay”
def translate(sent)
sent = sent.downcase
vowels = ['a', 'e', 'i', 'o', 'u']
words = sent.split(' ')
result = []
words.each_with_index do |word, i|
translation = ''
qu = false
if vowels.include? word[0]
translation = word + 'ay'
result.push(translation)
else
word = word.split('')
count = 0
word.each_with_index do |char, index|
if vowels.include? char
# handle words that start with 'qu'
if char == 'u' and translation[-1] == 'q'
qu = true
translation = words[i][count..words[i].length] + translation + 'ay'
result.push(translation)
next
end
break
else
# handle words with 'qu' in middle
if char == 'q' and translation[i-1] == 'u'
qu = true
translation = words[i][count +1..words[i].length] + 'ay'
result.push(translation)
next
else
translation += char
end
count += 1
end
end
# translation of consonant words without "qu"
if not qu
translation = words[i][count..words[i].length] + translation + 'ay'
result.push(translation)
end
end
end
result.join(' ')
end
puts translate("The quick brown fox")
However, I'm getting "ethay uickqay ownbray oxfay" instead of “Hetay uickqay rownbay oxfay”.
Where are the areas that needs correction? I couldn't pinpoint the problem. Could you show me the solution?
This is a very procedural and complex way of going about this. I'm not sure what your rules for checking q and u are for, since the pig latin translation rules make no mention of qu as a special case:
A far simpler way is to split the sentence into an array of words, and transform each word as required:
def translate(sent)
translation = sent.split(' ').map do |w|
vowels = %w(a e i o u)
word = w.downcase.split('')
if vowels.include? word[0]
"#{word}way"
else
"%s%say" % [word[1..-1], word[0]]
end
end
translation.join(' ').capitalize
end
puts translate("The quick brown fox")
# outputs Hetay uickqay rownbay oxfay
And, for 1.9 and likely above:
def translate(sent)
translation = sent.split(' ').map do |w|
vowels = %w(a e i o u)
word = w.downcase.split('')
if vowels.include? word[0]
"#{word.join}way"
else
"%s%say" % [word[1..-1].join, word[0]]
end
end
translation.join(' ').capitalize
end
puts translate("The quick brown fox")
Obviously, both of these are examples and can likely be made far better with work. But they serve to illustrate the point.
This makes use of map and join, and can probably be optimised further. The key difference between this method and yours is that you are attempting to build up a map of the translation iteratively, when you probably do not need to. Use the enumeration functions, they are part of what makes the functional programming style more expressive. Learn to think "how do I permute this data set to get my desired response" as opposed to "What steps do I need to perform to get my desired response".

Ruby Pig Latin Multiple Arguments

Hi I'm trying to write code for to convert strings to pig latin
def translate(str)
alpha = ('a'..'z').to_a
vowels = %w[a e i o u]
consonants = alpha - vowels
if vowels.include?(str[0])
str + 'ay'
elsif str[0..1] == 'qu'
str[2..-1]+'quay'
elsif consonants.include?(str[0]) && str[1..2]=='qu'
str[3..-1]+str[0..2]+'ay'
elsif consonants.include?(str[0]) && consonants.include?(str[1]) && consonants.include?(str[2])
str[3..-1] + str[0..2] + 'ay'
elsif consonants.include?(str[0]) && consonants.include?(str[1])
str[2..-1] + str[0..1] + 'ay'
elsif consonants.include?(str[0])
str[1..-1] + str[0] + 'ay'
elsif str[0..1] == 'qu'
str[2..-1]+'quay'
else
return str
end
end
This code works perfect for converting one word strings, for example: translate("monkey").
What i'm trying to do is make it possible for this code to accept multiple words as well (within the same string)...following the above criteria for converting into pig latin, example:
translate("please help") => "easeplay elphay"
thanks much!
Since you already know how to translate a single word why not just split up the task into two methods:
def translate(str)
str.split.map { |word| translate_word(word) }.join
end
def translate_word(str)
# Your old translate code here
end
What I would do for this is:
use the #split method to make your str variable into an array of words (or 1 word if its only 1 word).
afterwards you can use the array#each method to iterate through each array index.
i.e.
str = "hello"
str = str.split(" ") # str now equals ["hello"]
for multiple variables:
str = "hello world"
str- str.split(" ") #now equals ["hello", "world"]
then you can use the .each method:
str.each do |<variable name you want to use>|
<how you want to manipulate the array>
end
for the pig latin program you could do:
str.each do|element|
if vowels.include?(element)
<do whatever you want here>
elsif
<do whatever>
else
<do whatver>
end
end
this will iterate through each element in the array and translate it (if there is only one element it will still work)

Pig-Latin method translation

Trying to write Method in ruby that will translate a string in pig-latin , the rule :
Rule 1: If a word begins with a vowel sound, add an "ay" sound to the end of the word.
Rule 2: If a word begins with a consonant sound, move it to the end of the word, and then add an "ay" sound to the end of the word and also when the word begins with 2 consonants , move both to the end of the word and add an "ay"
As a newbie , my prob is the second rule , when the word begin with only one consonant it work , but for more than one , I have trouble to make it work ,Can somebody look at the code and let me know how i can code that differently and probably what is my mistake , probably the code need refactoring. Thanks , so far i come up with this code :
def translate (str)
str1="aeiou"
str2=(/\A[aeiou]/)
vowel = str1.scan(/\w/)
alpha =('a'..'z').to_a
con = (alpha - vowel).join
word = str.scan(/\w/)
if #first rule
str =~ str2
str + "ay"
elsif # second rule
str != str2
s = str.slice!(/^./)
str + s + "ay"
elsif
word[0.1]=~(/\A[con]/)
s = str.slice!(/^../)
str + s + "ay"
else
word[0..2]=~(/\A[con]/)
s = str.slice!(/^.../)
str + s + "ay"
end
end
translate("apple") should == "appleay"
translate("cherry") should == "errychay"
translate("three") should == "eethray"
No need for all those fancy regexes. Keep it simple.
def translate str
alpha = ('a'..'z').to_a
vowels = %w[a e i o u]
consonants = alpha - vowels
if vowels.include?(str[0])
str + 'ay'
elsif consonants.include?(str[0]) && consonants.include?(str[1])
str[2..-1] + str[0..1] + 'ay'
elsif consonants.include?(str[0])
str[1..-1] + str[0] + 'ay'
else
str # return unchanged
end
end
translate 'apple' # => "appleay"
translate 'cherry' # => "errychay"
translate 'dog' # => "ogday"
This will handle multiple words, punctuation, and words like 'queer' = 'eerquay' and 'school' = 'oolschay'.
def translate (sent)
vowels = %w{a e i o u}
sent.gsub(/(\A|\s)\w+/) do |str|
str.strip!
while not vowels.include? str[0] or (str[0] == 'u' and str[-1] == 'q')
str += str[0]
str = str[1..-1]
end
str = ' ' + str + 'ay'
end.strip
end
okay this is an epic pig latin translator that I'm sure could use a bit of refactoring, but passes the tests
def translate(sent)
sent = sent.downcase
vowels = ['a', 'e', 'i', 'o', 'u']
words = sent.split(' ')
result = []
words.each_with_index do |word, i|
translation = ''
qu = false
if vowels.include? word[0]
translation = word + 'ay'
result.push(translation)
else
word = word.split('')
count = 0
word.each_with_index do |char, index|
if vowels.include? char
# handle words that start with 'qu'
if char == 'u' and translation[-1] == 'q'
qu = true
translation = words[i][count + 1..words[i].length] + translation + 'uay'
result.push(translation)
next
end
break
else
# handle words with 'qu' in middle
if char == 'q' and word[i+1] == 'u'
qu = true
translation = words[i][count + 2..words[i].length] + 'quay'
result.push(translation)
next
else
translation += char
end
count += 1
end
end
# translation of consonant words without qu
if not qu
translation = words[i][count..words[i].length] + translation + 'ay'
result.push(translation)
end
end
end
result.join(' ')
end
So this will give the following:
puts translate('apple') # "appleay"
puts translate("quiet") # "ietquay"
puts translate("square") # "aresquay"
puts translate("the quick brown fox") # "ethay ickquay ownbray oxfay"
def translate(sentence)
sentence.split(" ").map do |word|
word = word.gsub("qu", " ")
word.gsub!(/^([^aeiou]*)(.*)/,'\2\1ay')
word = word.gsub(" ", "qu")
end
end
That was fun! I don't like the hack for qu, but I couldn't find a nice way to do that.
So for this pig latin clearly I skipped and\an\in and singular things like a\I etc. I know that wasn't the main question but you can just leave out that logic if it's not for your use case. Also this goes for triple consonants if you want to keep it with one or two consonants then change the expression from {1,3} to {1,2}
All pig latin is similar so just alter for your use case. This is a good opportunity to use MatchData objects. Also vowel?(first_letter=word[0].downcase) is a style choice made to be more literate so I don't have to remember that word[0] is the first letter.
My answer is originally based off of Sergio Tulentsev's answer in this thread.
def to_pig_latin(sentence)
sentence.gsub('.','').split(' ').collect do |word|
translate word
end.compact.join(' ')
end
def translate(word)
if word.length > 1
if word == 'and' || word == 'an' || word == 'in'
word
elsif capture = consonant_expression.match(word)
capture.post_match.to_s + capture.to_s + 'ay'
elsif vowel?(first_letter=word[0].downcase)
word + 'ay'
elsif vowel?(last_letter=word[-1].downcase)
move_last_letter(word) + 'ay'
end
else
word
end
end
# Move last letter to beginning of word
def move_last_letter(word)
word[-1] + word[0..-2]
end
private
def consonant_expression
# at the beginning of a String
# capture anything not a vowel (consonants)
# capture 1, 2 or 3 occurences
# ignore case and whitespace
/^ [^aeiou] {1,3}/ix
end
def vowel?(letter)
vowels.include?(letter)
end
def vowels
%w[a e i o u]
end
Also just for the heck of it I'll include my dump from a pry session so you all can see how to use MatchData. MINSWAN. It's stuff like this that makes ruby great.
pry > def consonant_expression
pry * /^ [^aeiou] {1,3}/ix
pry * end
=> :consonant_expression
pry > consonant_expression.match('Stream')
=> #<MatchData "Str">
pry > capture = _
=> #<MatchData "Str">
pry > ls capture
MatchData#methods:
== begin end hash length offset pre_match regexp string to_s
[] captures eql? inspect names post_match pretty_print size to_a values_at
pry >
pry > capture.post_match
=> "eam"
pry > capture
=> #<MatchData "Str">
pry > capture.to_s
=> "Str"
pry > capture.post_match.to_s
=> "eam"
pry > capture.post_match.to_s + capture.to_s + 'ay'
=> "eamStray"
pry >
If I understood your question correctly, you can just directly check if a character is a vowel or consonant and then use array ranges to get the part of the string you want.
vowels = ['a', 'e', 'i', 'o', 'u']
consonants = ('a'..'z').to_a - vowels
return str + "ay" if vowels.include?(str[0])
if consonants.include?(str[0])
return str[2..-1] + str[0..1] + "ay" if consonants.include?(str[1])
return str[1..-1] + str[0] + "ay"
end
str
Here's a solution that handles the "qu" phoneme as well as other irregular characters. Had a little trouble putting the individual words back into a string with the proper spacing. Would appreciate any feedback!
def translate(str)
vowels = ["a", "e", "i", "o", "u"]
new_word = ""
str.split.each do |word|
vowel_idx = 0
if vowels.include? word[0]
vowel_idx = 0
elsif word.include? "qu"
until word[vowel_idx-2]+word[vowel_idx-1] == "qu"
vowel_idx += 1
end
else
until vowels.include? word[vowel_idx]
vowel_idx += 1
end
end
idx_right = vowel_idx
while idx_right < word.length
new_word += word[idx_right]
idx_right += 1
end
idx_left = 0
while idx_left < vowel_idx
new_word += word[idx_left]
idx_left += 1
end
new_word += "ay "
end
new_word.chomp(" ")
end
I done gone did one too
def translate(string)
vowels = %w{a e i o u}
phrase = string.split(" ")
phrase.map! do |word|
letters = word.split("")
find_vowel = letters.index do |letter|
vowels.include?(letter)
end
#turn "square" into "aresquay"
if letters[find_vowel] == "u"
find_vowel += 1
end
letters.rotate!(find_vowel)
letters.push("ay")
letters.join
end
return phrase.join(" ")
end
def piglatinize(word)
vowels = %w{a e i o u}
word.each_char do |chr|
index = word.index(chr)
if index != 0 && vowels.include?(chr.downcase)
consonants = word.slice!(0..index-1)
return word + consonants + "ay"
elsif index == 0 && vowels.include?(chr.downcase)
return word + "ay"
end
end
end
def to_pig_latin(sentence)
sentence.split(" ").collect { |word| piglatinize(word) }.join(" ")
end
This seems to handle all that I've thrown at it including the 'qu' phoneme rule...
def translate str
letters = ('a'..'z').to_a
vowels = %w[a e i o u]
consonants = letters - vowels
str2 = str.gsub(/\w+/) do|word|
if vowels.include?(word.downcase[0])
word+'ay'
elsif (word.include? 'qu')
idx = word.index(/[aeio]/)
word = word[idx, word.length-idx] + word[0,idx]+ 'ay'
else
idx = word.index(/[aeiou]/)
word = word[idx, word.length-idx] + word[0,idx]+'ay'
end
end
end
I'm grabbing the words with the 'qu' phoneme and then checking all the other vowels [excluding u].
Then I split the word by the index of the first vowel (or vowel without 'u' for the 'qu' cases) and dropping the word part before that index to the back of the word. And adding 'ay' ftw.
Many of the examples here are fairly long. Here's some relatively short code I came up with. It handles all cases including the "qu" problem! Feedback always appreciated (I'm pretty new to coding).
$vowels = "aeiou"
#First, I define a method that handle's a word starting with a consonant
def consonant(s)
n = 0
while n < s.length
if $vowels.include?(s[n]) && s[n-1..n] != "qu"
return "#{s[n..-1]}#{s[0..n-1]}ay"
else
n += 1
end
end
end
#Then, I write the main translate method that decides how to approach the word.
def translate(s)
s.split.map{ |s| $vowels.include?(s[0]) ? "#{s}ay" : consonant(s) }.join(" ")
end

How to get words frequency in efficient way with ruby?

Sample input:
"I was 09809 home -- Yes! yes! You was"
and output:
{ 'yes' => 2, 'was' => 2, 'i' => 1, 'home' => 1, 'you' => 1 }
My code that does not work:
def get_words_f(myStr)
myStr=myStr.downcase.scan(/\w/).to_s;
h = Hash.new(0)
myStr.split.each do |w|
h[w] += 1
end
return h.to_a;
end
print get_words_f('I was 09809 home -- Yes! yes! You was');
This works but I am kinda new to Ruby too. There might be a better solution.
def count_words(string)
words = string.split(' ')
frequency = Hash.new(0)
words.each { |word| frequency[word.downcase] += 1 }
return frequency
end
Instead of .split(' '), you could also do .scan(/\w+/); however, .scan(/\w+/) would separate aren and t in "aren't", while .split(' ') won't.
Output of your example code:
print count_words('I was 09809 home -- Yes! yes! You was');
#{"i"=>1, "was"=>2, "09809"=>1, "home"=>1, "yes"=>2, "you"=>1}
def count_words(string)
string.scan(/\w+/).reduce(Hash.new(0)){|res,w| res[w.downcase]+=1;res}
end
Second variant:
def count_words(string)
string.scan(/\w+/).each_with_object(Hash.new(0)){|w,h| h[w.downcase]+=1}
end
def count_words(string)
Hash[
string.scan(/[a-zA-Z]+/)
.group_by{|word| word.downcase}
.map{|word, words|[word, words.size]}
]
end
puts count_words 'I was 09809 home -- Yes! yes! You was'
This code will ask you for input and then find the word frequency for you:
puts "enter some text man"
text = gets.chomp
words = text.split(" ")
frequencies = Hash.new(0)
words.each { |word| frequencies[word.downcase] += 1 }
frequencies = frequencies.sort_by {|a, b| b}
frequencies.reverse!
frequencies.each do |word, frequency|
puts word + " " + frequency.to_s
end
This works, and ignores the numbers:
def get_words(my_str)
my_str = my_str.scan(/\w+/)
h = Hash.new(0)
my_str.each do |s|
s = s.downcase
if s !~ /^[0-9]*\.?[0-9]+$/
h[s] += 1
end
end
return h
end
print get_words('I was there 1000 !')
puts '\n'
You can look at my code that splits the text into words. The basic code would look as follows:
sentence = "Ala ma kota za 5zł i 10$."
splitter = SRX::Polish::WordSplitter.new(sentence)
histogram = Hash.new(0)
splitter.each do |word,type|
histogram[word.downcase] += 1 if type == :word
end
p histogram
You should be careful if you wish to work with languages other than English, since in Ruby 1.9 the downcase won't work as you expected for letters such as 'Ł'.
class String
def frequency
self.scan(/[a-zA-Z]+/).each.with_object(Hash.new(0)) do |word, hash|
hash[word.downcase] += 1
end
end
end
puts "I was 09809 home -- Yes! yes! You was".frequency

Reverse a string in Ruby

How do you reverse a string in Ruby? I know about string#reverse. I'm interested in understanding how to write it in pure Ruby, preferably an in-place solution.
There's already an inplace reverse method, called "reverse!":
$ a = "abc"
$ a.reverse!
$ puts a
cba
If you want to do this manually try this (but it will probably not be multibyte-safe, eg UTF-8), and it will be slower:
class String
def reverse_inplace!
half_length = self.length / 2
half_length.times {|i| self[i], self[-i-1] = self[-i-1], self[i] }
self
end
end
This swaps every byte from the beginning with every byte from the end until both indexes meet at the center:
$ a = "abcd"
$ a.reverse_inplace!
$ puts a
dcba
Just for discussion, with that many alternates, it is good to see if there are major differences in speed/efficiency. I cleaned up the code a bit as the code showing output was repeatedly reversing the outputs.
# encoding: utf-8
require "benchmark"
reverse_proc = Proc.new { |reverse_me| reverse_me.chars.inject([]){|r,c| r.unshift c}.join }
class String
def reverse # !> method redefined; discarding old reverse
each_char.to_a.reverse.join
end
def reverse! # !> method redefined; discarding old reverse!
replace reverse
end
def reverse_inplace!
half_length = self.length / 2
half_length.times {|i| self[i], self[-i-1] = self[-i-1], self[i] }
end
end
def reverse(a)
(0...(a.length/2)).each {|i| a[i], a[a.length-i-1]=a[a.length-i-1], a[i]}
return a
end
def reverse_string(string) # method reverse_string with parameter 'string'
loop = string.length # int loop is equal to the string's length
word = '' # this is what we will use to output the reversed word
while loop > 0 # while loop is greater than 0, subtract loop by 1 and add the string's index of loop to 'word'
loop -= 1 # subtract 1 from loop
word += string[loop] # add the index with the int loop to word
end # end while loop
return word # return the reversed word
end # end the method
lorum = <<EOT
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent quis magna eu
lacus pulvinar vestibulum ut ac ante. Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Suspendisse et pretium orci. Phasellus congue iaculis
sollicitudin. Morbi in sapien mi, eget faucibus ipsum. Praesent pulvinar nibh
vitae sapien congue scelerisque. Aliquam sed aliquet velit. Praesent vulputate
facilisis dolor id ultricies. Phasellus ipsum justo, eleifend vel pretium nec,
pulvinar a justo. Phasellus erat velit, porta sit amet molestie non,
pellentesque a urna. Etiam at arcu lorem, non gravida leo. Suspendisse eu leo
nibh. Mauris ut diam eu lorem fringilla commodo. Aliquam at augue velit, id
viverra nunc.
EOT
And the results:
RUBY_VERSION # => "1.9.2"
name = "Marc-André"; reverse_proc.call(name) # => "érdnA-craM"
name = "Marc-André"; name.reverse! # => "érdnA-craM"
name = "Marc-André"; name.chars.inject([]){|s, c| s.unshift(c)}.join # => "érdnA-craM"
name = "Marc-André"; name.reverse_inplace!; name # => "érdnA-craM"
name = "Marc-André"; reverse(name) # => "érdnA-craM"
name = "Marc-André"; reverse_string(name) # => "érdnA-craM"
n = 5_000
Benchmark.bm(7) do |x|
x.report("1:") { n.times do; reverse_proc.call(lorum); end }
x.report("2:") { n.times do; lorum.reverse!; end }
x.report("3:") { n.times do; lorum.chars.inject([]){|s, c| s.unshift(c)}.join; end }
x.report("4:") { n.times do; lorum.reverse_inplace!; end }
x.report("5:") { n.times do; reverse(lorum); end }
x.report("6:") { n.times do; reverse_string(lorum); end }
end
# >> user system total real
# >> 1: 4.540000 0.000000 4.540000 ( 4.539138)
# >> 2: 2.080000 0.010000 2.090000 ( 2.084456)
# >> 3: 4.530000 0.010000 4.540000 ( 4.532124)
# >> 4: 7.010000 0.000000 7.010000 ( 7.015833)
# >> 5: 5.660000 0.010000 5.670000 ( 5.665812)
# >> 6: 3.990000 0.030000 4.020000 ( 4.021468)
It's interesting to me that the "C" version ("reverse_string()") is the fastest pure-Ruby version. #2 ("reverse!") is fastest but it's taking advantage of the [].reverse, which is in C.
Edit by Marc-André Lafortune *
Adding an extra test case (7):
def alt_reverse(string)
word = ""
chars = string.each_char.to_a
chars.size.times{word << chars.pop}
word
end
If the string is longer (lorum *= 10, n/=10), we can see that the difference widens because some functions are in O(n^2) while others (mine :-) are O(n):
user system total real
1: 10.500000 0.030000 10.530000 ( 10.524751)
2: 0.960000 0.000000 0.960000 ( 0.954972)
3: 10.630000 0.080000 10.710000 ( 10.721388)
4: 6.210000 0.060000 6.270000 ( 6.277207)
5: 4.210000 0.070000 4.280000 ( 4.268857)
6: 10.470000 3.540000 14.010000 ( 15.012420)
7: 1.600000 0.010000 1.610000 ( 1.601219)
The Ruby equivalent of the builtin reverse could look like:
# encoding: utf-8
class String
def reverse
each_char.to_a.reverse.join
end
def reverse!
replace reverse
end
end
str = "Marc-André"
str.reverse!
str # => "érdnA-craM"
str.reverse # => "Marc-André"
Note: this assumes Ruby 1.9, or else require "backports" and set $KCODE for UTF-8.
For a solution not involving reverse, one could do:
def alt_reverse(string)
word = ""
chars = string.each_char.to_a
chars.size.times{word << chars.pop}
word
end
Note: any solution using [] to access individual letters will be of order O(n^2); to access the 1000th letter, Ruby must go through the first 999 one by one to check for multibyte characters. It is thus important to use an iterator like each_char for a solution in O(n).
Another thing to avoid is to build intermediate values of increasing length; using += instead of << in alt_reverse would also make the solution O(n^2) instead of O(n).
Building an array with unshift will also make the solution O(n^2), because it implies recopying all existing elements one index higher each time one does an unshift.
Here's one way to do it with inject and unshift:
"Hello world".chars.inject([]) { |s, c| s.unshift(c) }.join
str = "something"
reverse = ""
str.length.times do |i|
reverse.insert(i, str[-1-i].chr)
end
"abcde".chars.reduce{|s,c| c + s } # => "edcba"
Use
def reverse_string(string) # Method reverse_string with parameter 'string'.
loop = string.length # int loop is equal to the string's length.
word = '' # This is what we will use to output the reversed word.
while loop > 0 # while loop is greater than 0, subtract loop by 1 and add the string's index of loop to 'word'.
loop -= 1 # Subtract 1 from loop.
word += string[loop] # Add the index with the int loop to word.
end # End while loop.
return word # Return the reversed word.
end # End the method.
def reverse(string)
result = ""
idx = string.length - 1
while idx >= 0
result << string [idx]
idx = idx - 1
end
result
end
The solution described below. There is no need to go beyond the half of array size:
class ReverseString
def initialize(array)
#array = array
#size = #array.size
end
def process
(0...#size/2).to_a.each_with_index do |e,i|
#array[i], #array[#size-i-1] = #array[#size-i-1], #array[i]
end
#array
end
end
require 'minitest/autorun'
class ReverseStringTest < Minitest::Unit::TestCase
def test_process
assert_equal "9876543210", ReverseString.new("0123456789").process
end
end
This is the solution that made the most sense to me as a ruby beginner
def reverse(string)
reversed_string = ''
i = 0
while i < string.length
reversed_string = string[i] + reversed_string
i += 1
end
reversed_string
end
p reverse("helter skelter")
Also, using Procs ...
Proc.new {|reverse_me| reverse_me.chars.inject([]){|r,c| r.unshift c}.join}.call("The house is blue")
=> "eulb si esuoh ehT"
Proc.new would be handy here because you could then nest your reversing algorithm (and still keep things on one line). This would be handy if, for instance, you needed to reverse each word in an already-reversed sentence:
# Define your reversing algorithm
reverser = Proc.new{|rev_me| rev_me.chars.inject([]){r,c| r.unshift c}.join}
# Run it twice - first on the entire sentence, then on each word
reverser.call("The house is blue").split.map {|w| reverser.call(w)}.join(' ')
=> "blue is house The"
Hard to read one-liner,
def reverse(a)
(0...(a.length/2)).each {|i| a[i], a[a.length-i-1]=a[a.length-i-1], a[i]}
return a
end
Consider looking at how Rubinius implements the method - they implement much of the core library in Ruby itself, and I wouldn't be surprised if String#reverse and String#reverse! is implemented in Ruby.
def palindrome(string)
s = string.gsub(/\W+/,'').downcase
t = s.chars.inject([]){|a,b| a.unshift(b)}.join
return true if(s == t)
false
end
If you have sentence "The greatest victory is that" and you want to have "that is victory greatest The" you should to use this method
def solution(sentance)
sentance.split.reverse.join(" ")
end
solution("The greatest victory is that")
Here's an alternative using the xor bitwise operations:
class String
def xor_reverse
len = self.length - 1
count = 0
while (count < len)
self[count] ^= self[len]
self[len] ^= self[count]
self[count] ^= self[len]
count += 1
len -= 1
end
self
end
"foobar".xor_reverse
=> raboof
In Ruby:
name = "Hello World"; reverse_proc.call(name)
name = "Hello World"; name.reverse!
name = "Hello World"; name.chars.inject([]){|s, c| s.unshift(c)}.join
name = "Hello World"; name.reverse_inplace!;
name = "Hello World"; reverse(name)
name = "Hello World"; reverse_string(name)
I believe this would work also
def reverse(str)
string = ''
(0..str.size-1).each do |i|
string << str[str.size - 1 - i]
end
string
end
def reverse(string)
reversed_string = ""
idx = 0
while idx < string.length
reversed_string = string[idx] + reversed_string
idx += 1
end
return reversed_string
end
string = "This is my string"
string_arr = string.split('')
n = string_arr.length
new_arr = Array.new
17.times do |i|
new_arr << string_arr.values_at(n - i)
end
reversed_string = new_arr.flatten.join('')
=> "gnirts ym si sihT"
Here is a simple alternative, it first breaks the string into an array, counts the length and subtracts one(because of ruby's indexing rule for array starting from 0), creates an empty variable, then runs an iteration on the keys of the array whilst appending the value of the array length minus current array index to the empty variable created and when it reaches the zeroth(sorry for my french) value it stops. Hope this helps.
class String
def rString
arr = self.split("")
len = arr.count - 1
final = ""
arr.each_index do |i|
final += arr[len - i]
end
final
end
end
A simple classic way with n/2 complexity
str = "Hello World!";
puts str;
for i in 0..(str.length/2).to_i
mid = (str.length-1-i);
temp = str[i];
str[i] = str[aa];
str[aa] = temp;
end
puts str;
we can use inject method to make it simple:
def reverse_str(str)
(1..str.length).inject('') {|rev_str, i| rev_str.concat(str[str.length-i])}
end
Note: I have used concat instead += because concat will change the string into same reference but += will create new object
for example
str = 'sanjay' #object.id #69080
str.concat('choudhary') #object.id #69080 #look here object id is same
str += 'choudhary' #object.id #78909 #look here object id will change.

Resources