Britt Flowers Britt Flowers - 2 months ago 8
Ruby Question

How do I iterate through an array and change characters efficiently?

I currently have this method in my work for a Ruby assignment where I need to change the vowels and consonants in a name put in by a user, to the next successive vowel/consonant, so ( a = e, e = i, etc.) and the same process for the consonants ( b = c, d = f, etc.). I did it the 'easy' way, but now I need to change it so that instead, I am iterating through an array and changing the vowels/consonants that way.

I am new to iteration so I am having trouble with this.

Here is my original method:

puts "What is your full name?"
full_name = gets.chomp

def vowelreplace(full_name)
vowels = 'aeiou'
replacements = 'eioua'
full_name.tr(vowels, replacements)
end

name_next_vowel = vowelreplace(full_name)

p name_next_vowel

def consonantreplace(name_next_vowel)
consonants = 'bcdfghjklmnpqrstvwxyz'
replacements = 'cdfghjklmnpqrstvwxyzb'
name_next_vowel.tr(consonants, replacements)
end

new_spyname = consonantreplace(name_next_vowel)

p new_spyname


Here's what I've started working with to change it below using an array and block method. Is there an easier less lengthy way of doing this? Is there a .next way of doing this, or in general, a more efficient way?

puts "What is your first name?"
first_name = gets.chomp

arr = first_name.split("")

p arr

arr.map! { |element|
if(element == "a")
"e"
elsif(element == "e")
"i"
elsif(element == "i")
"o"
elsif(element == "o")
"u"
elsif(element == "u")
"a"
else
element
end
}

p arr

new_arr = arr

new_arr.map! { |element|
if(element == "b")
"c"
elsif(element == "c")
"d"
elsif(element == "d")
"f"
elsif(element == "f")
"g"
elsif(element == "g")
"h"
elsif(element == "h")
"j"
elsif(element == "j")
"k"
elsif(element == "k")
"l"
elsif(element == "l")
"m"
elsif(element == "m")
"n"
elsif(element == "n")
"p"
elsif(element == "p")
"q"
elsif(element == "q")
"r"
elsif(element == "r")
"s"
elsif(element == "s")
"t"
elsif(element == "t")
"v"
elsif(element == "v")
"w"
elsif(element == "w")
"x"
elsif(element == "x")
"y"
elsif(element == "y")
"z"
elsif(element == "z")
"b"
else
element
end
}

p new_arr

arr.join("")

Answer Source

I like the tr approach, but if you want something similar to next, then Array#rotate could be a good option; here's an example:

def letter_swap(full_name)
  vowels     = %w(a e i o u)
  consonants = %w(b c d f g h j k l m n p q r s t v w x y z)

  full_name.each_char.with_object("") do |char, new_name|
    if vowels.include?(char)
      new_name << vowels.rotate(vowels.index(char) + 1).first
    elsif consonants.include?(char)
      new_name << consonants.rotate(consonants.index(char) + 1).first
    else
      new_name << char
    end
  end
end

Of course you could DRY this code, but at the expense of readability (IMO); for example:

def letter_swap(full_name)
  letters = [%w(a e i o u), %w(b c d f g h j k l m n p q r s t v w x y z)]

  full_name.each_char.with_object("") do |char, new_name|
    group = letters.find { |group| group.include?(char) }
    new_name << (group.nil? ? char : group.rotate(group.index(char) + 1).first)
  end
end