1

I have a method that takes in a string as an argument, replaces each letter with the next letter in the alphabet and then capitalizes every vowel. I have gotten both of those to work individually (the replacing and capitalization), but at this point, I just don't know how to make them work together.

def LetterChanges(str)
    new_str = str.downcase.split("")
    new_str.each do |x|
        x.next!
    end
    new_str.to_s.tr!('aeiou','AEIOU')
    return new_str.join("")
end

LetterChanges("abcdef")
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
dwhipple
  • 39
  • 4

6 Answers6

4

new_str.to_s is not stored anywhere. It doesn't affect the original array.

return new_str.join("").tr('aeiou', 'AEIOU')

This will convert the array back to a string and you can operate on that and return it.

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • 1
    Or just `str.downcase.split('').map(&:next).join.tr('aeiou','AEIOU')`. [Demo](http://repl.it/y3j) – potashin Jul 24 '15 at 02:36
  • Thank you much! That makes so much more sense to me now. Also @suslov, what exactly is the &: before the next? I've seen that in sample code, but its been difficult to research what exactly that does. I've seen and used `inject(:*)` before, which seems similar to that. Thanks again. Very clean and elegant solution. :) – dwhipple Jul 24 '15 at 02:43
  • @dwhipple: you are welcome, there is good explanation about `&` shorthand [here](http://stackoverflow.com/q/1217088/3444240). – potashin Jul 24 '15 at 02:47
  • `join("")` is equivalent to `join` (i.e. unless you change `$,`) – Stefan Jul 24 '15 at 08:07
1

That could be resolved with gsub.

"abcdef".gsub(/./){|char| char.next}.gsub(/[aeiou]/){|vowel| vowel.upcase}
#=> "bcdEfg" 

so that method could be

def letter_changes_gsub(str)
  str.gsub(/./){|char| char.next}.gsub(/[aeiou]/){|vowel| vowel.upcase}
end

That is faster and more simple that work with arrays.

Horacio
  • 2,865
  • 1
  • 14
  • 24
1

Other answers already showed you how to combine both parts of your code. But there's another issue: String#next is continuing witch "aa" after "z":

"z".next #=> "aa"

You could add an if statement to handle this case:

str.chars.map do |char|
  if char == 'z'
    'a'
  else
    char.next
  end
end.join

or:

str.chars.map { |char| char == 'z' ? 'a' : char.next }.join

But there's a much simpler way: let String#tr perform the entire substitution:

str.downcase.tr('a-z', 'bcdEfghIjklmnOpqrstUvwxyzA')

Or slightly shorter:

str.downcase.tr('a-z', 'bcdEfghIjk-nOp-tUv-zA')
Community
  • 1
  • 1
Stefan
  • 109,145
  • 14
  • 143
  • 218
0
2.1.0 :012 > 'abcdef'.split('').map(&:next).join.tr('aeiou', 'AEIOU')
 => "bcdEfg"

I would not recommend doing this in one line, of course. But to get at your confusion of how these methods might string together, here is one solution that works. When in doubt, use IRB to call each method and watch how Ruby responds. That will help you figure out where your code is breaking down.

In practice, I would break this into multiple methods. It's too many things for one method to do. And also a lot harder to find bugs (and test), as you found out.

def rotate(string)
  string.split('').map(&:next).join
end

def capitalize_vowels(string)
  string.tr('aeiou', 'AEIOU')
end
Jake Worth
  • 5,490
  • 1
  • 25
  • 35
  • Why do I often see (sic) "you can do that with the following one-liner". That's akin to a waiter serving me a plate of food and then commenting, " Here is your dinner." Does the waiter think I may not realize that I am to eat it, or wants to be clear that it's for me and not for another patron? Aren't some things just plain obvious? – Cary Swoveland Jul 24 '15 at 03:30
  • @CarySwoveland it looks like it's a proviso that you shouldn't really do it as a one-liner. – Andrew Grimm Jul 24 '15 at 03:48
0

How about:

def string_thing(string)
    string.downcase.tr('abcdefghijklmnopqrstuvwxyz','bcdEfghIjklmnOpqrstUvwxyzA')
end

#tr just will replace each character in the first parameter with the corresponding one in the second parameter.

Charles
  • 1,384
  • 11
  • 18
0

This can be achieved with the combination of gsub and tr:

"abcdef".gsub(/[A-z]/) { |char| char.next }.tr('aeiou', 'AEIOU')
#=> "bcdEfg"
"Fun times!".gsub(/[A-z]/) { |char| char.next }.tr('aeiou', 'AEIOU')
#=> "GvO Ujnft!"
Baxter
  • 142
  • 6