【问题标题】:Count vowels in a string with ruby用 ruby​​ 计算字符串中的元音
【发布时间】:2018-04-30 19:06:37
【问题描述】:

我的目标是返回给定字符串中元音的数量。我试过这段代码:

def count_vowels(string)
  vowels = ['a', 'e', 'i', 'o', 'u']
  chars_ary = string.split(//)
  ary_with_vowels = chars_ary.take_while {|letter| vowels.include?(letter)}
  return ary_with_vowels.length
end

它没有通过大多数测试用例。我知道有多种其他方法可以解决此问题,但我想使用我提供的代码来解决它。

有人可以告诉我为什么这不起作用吗?

【问题讨论】:

  • 对哪个测试用例不起作用?
  • 在字符串不以'a'开头并且只有'a'作为元音的测试用例失败,因为一旦条件返回false,迭代就会中断。 @meagar 解释得最好,我使用了错误的方法。
  • 您也没有处理带有大写元音的字符串。你应该这样做chars_ary = string.downcase.split(//)
  • 你知道String#count吗?即string.count('aeiou')
  • 我想你可以写string.scan(/[aeiou]/i).size

标签: ruby iteration


【解决方案1】:

尝试这样的事情,它查看元音数组中的每个字符,并将其与字符串中的每个字符进行比较,如果条件为真,则将其与 p 进行比较。

def vowles(string)
arr = []
vowels = %w(a e i o u)
vowels.each do |x|
    if string.each_char { |letter| (arr << x) if x == letter }
    end
  end
  p "#{arr} has #{arr.count} vowels"
end
vowles("wwwweeeeeee")

或者更高效的

def vowels(string)
  p string.scan(/[a e i o u]/).count
end
vowels("hello world")

【讨论】:

    【解决方案2】:

    让我们对几种方法进行基准测试。

    require 'fruity'
    require 'set'
    
    SET_OF_VOWELS = %w| a e i o u |.to_set
    
    def string_count(str)
      str.count('aeiou')
    end
    
    def set_include?(str)
      str.each_char.count { |c| SET_OF_VOWELS.include?(c) }
    end
    
    def use_hash(str)
      h = str.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }
      SET_OF_VOWELS.sum { |c| h[c] }
    end
    
    alpha = ('a'..'z').to_a
    
    [1_000, 10_000, 100_000, 1_000_000].each do |n|
    
      puts "\nString length = #{n}"     
      str = Array.new(n) { alpha.sample }.join
    
      compare(
        string_count: -> { string_count(str) },
        set_include?: -> { set_include?(str) },
        use_hash:     -> { use_hash(str) }
      )
    end    
    

    结果如下。

    String length = 1000
    Running each test 1024 times. Test will take about 9 seconds.
    string_count is faster than set_include? by 159x ± 1.0
    set_include? is faster than use_hash by 37.999999999999986% ± 1.0%
    
    String length = 10000
    Running each test 128 times. Test will take about 11 seconds.
    string_count is faster than set_include? by 234x ± 1.0
    set_include? is faster than use_hash by 35.00000000000001% ± 1.0%
    
    String length = 100000
    Running each test 16 times. Test will take about 14 seconds.
    string_count is faster than set_include? by 246x ± 1.0
    set_include? is faster than use_hash by 35.00000000000001% ± 1.0%
    
    String length = 1000000
    Running each test 2 times. Test will take about 18 seconds.
    string_count is faster than set_include? by 247x ± 1.0
    set_include? is faster than use_hash by 34.00000000000001% ± 1.0%
    

    【讨论】:

      【解决方案3】:

      这种方式比较容易:

       def count_vowels(string)
         string.count('aeiou')
       end
      

      【讨论】:

      • 我会在其中抛出一个.downcase(或在计数字符串中添加“AEIOU”),但这是解决一般问题的最佳方法。
      • 由于 OP 也没有在寻找大写元音,所以我保持这种方式。走到这一步,人们还会考虑是否也应将 ü 或 æ 或 η 或 あ 或 ø 视为元音。我不是语言学家,也不知道元音的概念究竟是如何映射到整个 Unicode 字符集的,所以我最好把这个决定留给 OP。
      【解决方案4】:

      take_while 在这里是错误的方法。它从头开始,只要块返回一个真实值,就“接受”元素。当您第一次遇到不是元音的字母时,它就会停止。

      你想要select,它选择块返回真值的所有元素。

      【讨论】:

      • 完全正确!我回到文档阅读了 take_whiles 实现,这正是你所描述的,我读得太快了。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2013-11-26
      • 2020-02-19
      • 2011-09-05
      • 2022-08-13
      • 2012-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多