如何迭代数组并有效地更改字符?

时间:2017-08-20 22:03:08

标签: arrays ruby loops iteration

我目前在我的工作中有这个方法用于Ruby任务,我需要将用户输入的名称中的元音和辅音更改为下一个连续的元音/辅音,所以(a = e,e = i等等)和辅音的相同过程(b = c,d = f等)。我用“简单”的方式做到了,但现在我需要改变它,相反,我正在迭代一个数组并改变元音/辅音。

我是迭代的新手,所以我遇到了麻烦。

这是我原来的方法:

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

以下是我开始使用数组和块方法在下面进行更改的内容。这样做是否有更简单的冗长方式?是否有一种.next方式这样做,或者一般来说,更有效的方式?

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("")

3 个答案:

答案 0 :(得分:1)

你可以在地图循环中使用一系列case语句吗?

arr.map! { |element|
  case element
    when "a" then "e"
    when "e" then "i"
    when "i" then "o"
    when "o" then "u"
    when "u" then "a"
  end
}

辅音也一样。

答案 1 :(得分:1)

我喜欢tr方法,但是如果你想要类似于next的东西,那么Array#rotate可能是一个不错的选择;这是一个例子:

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

当然你可以干这个代码,但代价是可读性(IMO);例如:

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

答案 2 :(得分:1)

您可以将String#tr与字符数组一样使用,但tr的时间复杂度为O(n),因为第一个参数的字符在尝试时会按顺序检查找到匹配。如果要进行大量此类查找,则使用具有几乎恒定的查找时间的散列会快得多。您可以编写如下方法。

<强>代码

VOWELS = %w|a e i o u|
  #=> ["a", "e", "i", "o", "u"]
NEXT_VOWEL = VOWELS.zip(VOWELS.rotate(1)).to_h
  #=> {"a"=>"e", "e"=>"i", "i"=>"o", "o"=>"u", "u"=>"a"}
CONSONANTS = ('a'..'z').to_a - VOWELS
  #=> ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n",
  #    "p", "q", "r", "s", "t", "v", "w", "x", "y", "z"]
NEXT_CONSONANT = CONSONANTS.zip(CONSONANTS.rotate(1)).to_h
  #=> {"b"=>"c", "c"=>"d", "d"=>"f", "f"=>"g", "g"=>"h", "h"=>"j", "j"=>"k",
  #    "k"=>"l", "l"=>"m", "m"=>"n", "n"=>"p", "p"=>"q", "q"=>"r", "r"=>"s",
  #    "s"=>"t", "t"=>"v", "v"=>"w", "w"=>"x", "x"=>"y", "y"=>"z", "z"=>"b"}

def code(arr)
  arr.map { |c| NEXT_CONSONANT[c] || NEXT_VOWEL[c] || c }
end

据推测,你也需要能够解码。您可以使用方法Hash#invert编写解码方法,如下所示。

PREVIOUS_VOWEL = NEXT_VOWEL.invert
  # => {"e"=>"a", "i"=>"e", "o"=>"i", "u"=>"o", "a"=>"u"}
PREVIOUS_CONSONANT = NEXT_CONSONANT.invert
  #=> {"c"=>"b", "d"=>"c", "f"=>"d", "g"=>"f", "h"=>"g", "j"=>"h", "k"=>"j", "l"=>"k",
  #    "m"=>"l", "n"=>"m", "p"=>"n", "q"=>"p", "r"=>"q", "s"=>"r", "t"=>"s", "v"=>"t",
  #    "w"=>"v", "x"=>"w", "y"=>"x", "z"=>"y", "b"=>"z"}

def decode(arr)
  arr.map { |c| PREVIOUS_CONSONANT[c] || PREVIOUS_VOWEL[c] || c }
end

示例

首先编码数组。

arr = "billy-bob".chars
  #=> ["b", "i", "l", "l", "y", "-", "b", "o", "b"]
a = code(arr)
  #=> ["c", "o", "m", "m", "z", "-", "c", "u", "c"]
a.join
  #=> "commz-cuc"

然后解码它。

a = decode ["c", "o", "m", "m", "z", "-", "c", "u", "c"]
  #=> ["b", "i", "l", "l", "y", "-", "b", "o", "b"]
a.join
  #=> "billy-bob"

<强>解释

考虑表达式

NEXT_CONSONANT[c] || NEXT_VOWEL[c] || c
方法code中的

。假设c = 'd'。然后是NEXT_COSONANT['d'] #=> 'f',所以我们有

'f' || NEXT_VOWEL[c] || c

由于'f'是真实的,因此会返回'f'。 Ruby没有理由评估NEXT_VOWEL[c] || c所以她没有。

现在假设c = 'e'。然后,由于NEXT_CONSONANT没有键'e'NEXT_CONSONANT['e'] #=> nil,表达式变为

nil || NEXT_VOWEL[c] || c

因此有必要评估NEXT_VOWEL['e']。如果返回'i',这是真实的,则会返回'i',并且无需评估c

最后,如果c = '-',我们会获得

nil || nil || c

因此评估并返回c