【问题标题】:Replacing letters in string with their numeric position in the alphabet in ruby用红宝石字母表中的数字位置替换字符串中的字母
【发布时间】:2021-05-01 11:26:48
【问题描述】:

我正在尝试创建一个方法,给定一个字符串,用它在字母表中的位置替换每个字母。

如果文本中的任何内容不是字母,我想忽略它而不返回它。

"a" = 1, "b" = 2, etc.

例子

alphabet_position("The sunset sets at twelve o' clock.")

应该返回"20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"(作为字符串) 我试过了,但没有用:

    def alphabet_position(text)
      alph = ("a".."z").to_a
      text = text.split(/./).map {|ch| if ch.in?(alph)
        ((alph.index[ch]).to_i+1).to_s
        else
          ""
        end
      }.join(" ").strip
    end

提前致谢!

【问题讨论】:

    标签: ruby string indexing methods replace


    【解决方案1】:

    首先我们可以构建翻译,因为哈希查找非常快:

    # alternatively letter_to_number = ('a'..'z').each.with_index(1).to_h
    letter_to_number = ('a'..'z').zip(1..26).to_h 
    #=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6, 
    #    "g"=>7, "h"=>8, "i"=>9, "j"=>10, "k"=>11, "l"=>12, 
    #    "m"=>13, "n"=>14, "o"=>15, "p"=>16, "q"=>17, "r"=>18, 
    #    "s"=>19, "t"=>20, "u"=>21, "v"=>22, "w"=>23, "x"=>24, "y"=>25, "z"=>26}
    

    然后把它们换掉

    # ruby >= 2.7 
    text.downcase.each_char.filter_map {|c| letter_to_number[c] }.join(' ')
    # ruby < 2.7 
    text.downcase.each_char.map {|c| letter_to_number[c] }.compact.join(' ')
    #=> "20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
    

    【讨论】:

      【解决方案2】:
      def convert(str)
        str.downcase.each_char.with_object('') do |c,s|
          n = c.ord
          if n.between?(97, 122)
            s << ' ' unless s.empty?
            s << (n-96).to_s
          end
        end
      end
      
      convert "Sunset was at twelve o'clock, somewhere, on some day"
        #=> "19 21 14 19 5 20 23 1 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11 19 15 13 5 23 8 5 18 5 15 14 19 15 13 5 4 1 25"
      

      女士们,先生们,启动你的引擎!

      def alphabet_position(text)
        text.downcase.split('').map do |letter|
          index = ('a'..'z').find_index(letter)
          index + 1 if index
        end.compact.join(' ')
      end
      
      def smnky_1_7(str)
        letter_to_number = ('a'..'z').zip(1..26).to_h
        str.downcase.each_char.filter_map {|c| letter_to_number[c] }.join(' ')
      end
      
      def smnky_pre_1_7(str)
        letter_to_number = ('a'..'z').zip(1..26).to_h
        str.downcase.each_char.map {|c| letter_to_number[c] }.compact.join(' ')
      end
      
      LETTER_TO_NUMBER = ('a'..'z').zip(1..26).to_h
      def smnky_pre_w_constant(str)
        str.downcase.each_char.map {|c| LETTER_TO_NUMBER[c] }.compact.join(' ')
      end
      
      def convert_with_arr(str)
        str.downcase.each_char.with_object([]) do |c,arr|
          n = c.ord
          arr << n - 96 if n.between?(97, 122)
        end.join(' ')
      end
      
      str = "Sunset was at twelve o'clock, somewhere, on some day"
      
      require 'benchmark'
      
      def run(m, str)
        500.times { method(m).call(str) }
      end
      
      Benchmark.bm(19) do |x|
        x.report("Cary")                 { run(:convert, str) }
        x.report("Tatiana")              { run(:alphabet_position, str) }
        x.report("smnky 1.7")            { run(:smnky_1_7, str) }
        x.report("smnky pre 1.7")        { run(:smnky_1_7, str) }
        x.report("smnky pre w/constant") { run(:smnky_pre_w_constant, str) }
        x.report("Cary with arr")        { run(:convert_with_arr, str) }
      end
      
                                user     system      total        real
      Cary                  0.018610   0.000300   0.018910 (  0.019135)
      Tatiana               0.067738   0.001138   0.068876 (  0.070317)
      smnky 1.7             0.028659   0.001035   0.029694 (  0.030583)
      smnky pre 1.7         0.032050   0.001662   0.033712 (  0.035089)
      smnky pre w/constant  0.013705   0.000323   0.014028 (  0.014139)
      Cary with arr         0.016989   0.000538   0.017527 (  0.017925)
      

      【讨论】:

      • 不知道您是否尝试过,但我发现 fruity gem 在基准测试方面比内置的更好。对常量 btw 的良好调用除了它提供了不公平的优势alphabet_position 可以实现相同的功能。
      • @engineersmnky,我已经使用了很多fruity,并且在我在这里的经验之后会回到它。最初,我有效地拥有1.times { method(m).call(str) },并且从一次运行到下一次运行的结果遍布整个地图。定义一个常数似乎是公平的,因为这种方法通常会被多次调用。我不关注你对 alphabet_position 的评论。
      • 我的意思是,正如我在帖子下评论的那样,范围 (('a'..'z')) 可以在循环之外构建,在这种情况下,可以在方法本身之外构建(这是额外时间的地方节省介于smnky_pre_1_7smnky_pre_w_constant 之间)。这也是我喜欢fruity 的原因,因为它是确定性的,您不必过多关注运行次数或运行之间的个体差异。
      • @engineersmnky,是的,但是find_index 仍然是线性搜索,不是吗?
      • 带有果味的 smnky_pre_2_7_w_constant 类似于 cary_with_arr; cary_with_arr 类似于 cary; cary 比 smnky_pre_2_7 快 3x ± 1.0; smnky_pre_2_7 比 tatiana 快 2x ± 1.0; Example *repl.it 仍在使用 2.5.1,所以我不得不删除 2.7 选项。
      【解决方案3】:

      为了调试一段代码,逐行运行。很快你就会发现:

      text = "The sunset sets at twelve o' clock."
      text.split(/./) #=> []
      

      它不会做你认为它做的事情。

      我认为您的意思是其中之一:

      text.split('') #=> ["T", "h", "e", " ", ...
      text.chars #=> ["T", "h", "e", " ", ...
      

      还有几个错误,但我会留给您解决。

      【讨论】:

        【解决方案4】:
            def alphabet_position(text)
              text.downcase.split('').map do |letter|
                index = ('a'..'z').find_index(letter)
                index + 1 if index
              end.compact.join(' ')
            end
        

        【讨论】:

        • 您可能希望在循环之外构建('a'..'z'),这样您就不会创建 N 等于 text.size 的 N 个范围。
        • 我不知道这很重要,但是您不需要对范围进行线性扫描以获取字符在字母表中的偏移量,因为您可以减去ASCII码。不知道如何在红宝石中做到这一点。另外,在第 4 行,ruby 中的 0 是真的吗? 'a' 可能存在错误。
        【解决方案5】:

        按照@Siim Liiser 的回答,您也可以使用扫描方法来获取信件。

        text = "The sunset sets at twelve o' clock."
        irb(main):002:0> text.scan(/[a-z]/)
        => ["h", "e", "s", "u", "n", "s", "e", "t", "s", "e", "t", "s", "a", "t", "t", "w", "e", "l", "v", "e", "o", "c", "l", "o", "c", "k"]
        
        

        如您所见,字母 T 是大写的并且丢失了,为了解决这个问题,您可以在调用方法 scan 之前使用小写:

        irb(main):004:0> text.downcase.scan(/[a-z]/)
        => ["t", "h", "e", "s", "u", "n", "s", "e", "t", "s", "e", "t", "s", "a", "t", "t", "w", "e", "l", "v", "e", "o", "c", "l", "o", "c", "k"]
        
        

        【讨论】:

          猜你喜欢
          • 2016-01-20
          • 1970-01-01
          • 2019-10-23
          • 2017-05-16
          • 1970-01-01
          • 2012-05-31
          • 2013-12-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多