算法删除元音,意外结果



我正在尝试构建一种从字符串中删除元音的算法。下面的代码是我到目前为止所拥有的。

def shortcut(s)
  s = s.split("")
  for i in 0..s.length - 1 do
    if ["a","e","i","o","u"].include?(s[i])
      s.delete_at(i)
    end
  end
  s.join
end

puts shortcut("hello world, we are the champions")
# => hll wrld, w r th chmpons

为什么没有从字符串中删除'o'

删除字符后,索引将变为无效。

hello
  ^    before delete
01234
  v    after delete
hllo

您可以从头到尾迭代以解决它。

def shortcut(s)
  s = s.split("")
  (s.length - 1).downto(0) do |i|
    if ["a","e","i","o","u"].include?(s[i])
      s.delete_at(i)
    end
  end
  s.join
end

但更好的解决方案是使用字符串替换方法,如 String#deleteString#gsub

"hello world, we are the champions".gsub(/[aeiou]/, '')
=> "hll wrld, w r th chmpns"

在迭代数组时,您正在从数组s中删除元素。那会给你意想不到的结果。

请改用String#delete

"hello world, we are the champions".delete('aeiou')
# => "hll wrld, w r th chmpns" 

当您从数组中删除元素时,您的迭代器 i 可以大于到达数组末尾之前的大小。

最短的方法

def shortcut(s)
  s.gsub(/[aeiou]/i, '')
end
shortcut('hello world, we are the champions')
#=> "hll wrld, w r th chmpns"

您也可以使用 Array#Select。

def shortcut(s)
  s.chars.select{|s| s !~ /[aeiou]/ }.join('')
end
## OR
def shortcut(s)
  s.chars.select{ |s| s if !["a","e","i","o","u"].include?(s) }.join('')
end
shortcut("hello world, we are the champions")
## OUTPUT
 => "hll wrld, w r th chmpns"

如果您研究以下简化示例,您将了解为什么删除要迭代的数组的元素会导致您获得的结果。

s = "two lions"
s = s.split("")
puts "s.split=#{s}"
for i in 0..s.length - 1 do
  puts "i=#{i}"
  str = s[i]
  puts "  str=/#{str}/"
  if ["a","e","i","o","u"].include?(s[i])
    puts "  str is a vowel"
    s.delete_at(i)
    puts "  s after delete_at(#{i})=#{s}"
  end
end
puts "s after loop=#{s}"
puts "s.join=#{s.join}"
s.join

指纹

s.split=["t", "w", "o", " ", "l", "i", "o", "n", "s"]
i=0
  str=/t/
i=1
  str=/w/
i=2
  str=/o/
  str is a vowel
  s after delete_at(2)=["t", "w", " ", "l", "i", "o", "n", "s"]

空间被跳过。

i=3
  str=/l/
i=4
  str=/i/
  str is a vowel
  s after delete_at(4)=["t", "w", " ", "l", "o", "n", "s"]
"

O"现在位于索引 4,"N"位于索引 5。

i=5
  str=/n/
i=6
  str=/s/
i=7
  str=//
i=8
  str=//
s after loop=["t", "w", " ", "l", "o", "n", "s"]
s.join=tw lons

你的方法可以是

def shortcut(s)
  s = s.split("")
  for i in 0..s.length - 1 do
    s.delete(s[i]) if ["a","e","i","o","u"].include? s[i]
  end
  s.join
end

> shortcut("hello world, we are the champions")
=> "hll wrld, w r th chmpns"

另一种方式

> s = "hello world, we are the champions"
> (s.split("") - s.scan(/[aeiou]/)).join
=> "hll wrld, w r th chmpns"