【问题标题】:Ruby method conditionsRuby方法条件
【发布时间】:2015-12-26 01:08:44
【问题描述】:

我的程序的说明是创建一个方法,该方法接受一个字符串并返回任何奇数周围的破折号,但最终结果可能不是以破折号"-" 开头或结尾的例外。例如,如果我输入"95601137",它应该返回

"9 - 5 - 6 0 - 1 - 1 - 3 - 7"

代码如下:

def dashes(number)
  string = number.to_s
  i=0
  final = []
  while i<string.length
    digit = string[i].to_i
    if ((digit)%2 != 0) && (i==0) && (string.length == 1) && ((string.length - 1) == 0)
      final.push(string[i])
    elsif ((digit)%2 != 0) && (i==0) && (string.length != 1) && ((string.length - 1) > 0)
      final.push(string[i] + "-")
    elsif ((digit)%2 != 0) && (i>0) && (i!=(string.length - 1)) && ((string.length != 1))
      final.push("-" + string[i] + "-")
    elsif ((digit)%2 != 0) && (i!=0) && (i==(string.length - 1))
      final.push("-" + string[i])
    else final.push(string[i])
    end
    i+=1
  end
  return final
end

puts("Give me any number.")
answer = gets
puts dashes(answer)

我的程序有两个问题:

  1. 当我输入9 时,它返回"9-"。怎么会?
  2. 当我输入一个以奇数结尾的字符串时,它会在末尾添加一个破折号,这是意料之外的。我以为我的if 条件也很严格。

【问题讨论】:

  • 非常感谢大家的帮助!

标签: ruby methods


【解决方案1】:

我想提出另一个解决方案:

def dashes(num)
  str = num.to_s
  dashed_arr = str.chars.map.with_index do |digit, index|
    next digit if digit.to_i.even?
    if index.zero? # is it first digit?
      "#{digit} -"
    elsif index == str.length - 1 # is it last digit?
      "- #{digit}"
    else 
      "- #{digit} -"
    end
  end

  dashed_arr.join(' ').gsub('- -', '-')
end

puts dashes(95601137)
puts dashes(909)
# => "9 - 5 - 6 0 - 1 - 1 - 3 - 7"
# => "9 - 0 - 9"

让我们一步一步回顾:

  1. str = num.to_s - 将我们的数字转换为字符串表示,即"95601137"
  2. str.chars - 用字符分割我们的字符串。我们得到一个字符数组,如下所示:["9", "5", "6", "0", "1", "1", "3", "7"],因为我们想要一个一个地迭代它们。
  3. map 获取一个数组并通过do ... end 中提供的代码将其转换为另一个数组。

我们以这段代码为例:

[1, 2, 3].map do |num| 
  num * 2 
end
# => [2, 4, 6]

如果您还需要元素的索引,您可以类似地使用.map.with_index(索引从零开始):

[1, 2, 3].map.with_index do |num, index| 
  num * index # index takes values 0, 1, 2
end 
# => [0, 2, 6]

因此,在上面的代码块中,我们将号码中的每个数字都设为 digit,并将其从 0 开始的位置设为 index

  1. next digit if digit.to_i.even?。我们不需要偶数,所以我们可以跳过它们。将digit 转换为整数需要.to_i,因此我们可以查询它是偶数还是奇数。 next digit 只返回当前数字并将执行移至下一个数字。

  2. 现在我们只剩下奇数位了,所以我们只需要根据数字位置正确放置破折号:如果是第一个数字,则附加一个破折号,如果是最后一个数字,则将破折号放在前面数字,否则只需用破折号包围数字:

    if index.zero? # first digit, index is zero-based
      "#{digit} -"
    elsif index == str.length - 1 # last digit
      "- #{digit}"
    else 
      "- #{digit} -"
    end
    
  3. 我们将中间结果保存在dashed_arr 变量中,以使代码可读。现在它包含以下内容:["9 -", "- 5 -", "6", "0", "- 1 -", "- 1 -", "- 3 -", "- 7"]。如您所见,我们几乎完成了,我们只需要将数组的所有元素连接回字符串。

  4. dashed_arr.join(' ')。将数组的元素返回到一个字符串中,以单个空格作为分隔符。我们得到这个字符串:9 - - 5 - 6 0 - 1 - - 1 - - 3 - - 7。嗯,看来我们需要删除一些连续的破折号。

  5. 让我们使用gsubdashed_arr.join(' ').gsub('- -', '-')gsub 只是搜索所有出现的第一个字符串并用第二个字符串替换它们,这正是我们需要的:9 - 5 - 6 0 - 1 - 1 - 3 - 7

我们完成了!我希望你和我一样有趣。

【讨论】:

  • 如果您输入“909”,则输出为“909”。我不确定,但从我对问题的理解来看,输出必须是“9 - 0 - 9”
  • @Wagner 看来你是对的,我会更新我的答案。
【解决方案2】:

另一个实现,灵感来自Cary Swoveland's first implementation

str = '95601137'

separators = str.each_char.map(&:to_i).each_cons(2).map do |pair| 
  pair.any?(&:odd?) ? ' - ' : ' '
end

str.chars.zip(separators).join
# => "9 - 5 - 6 0 - 1 - 1 - 3 - 7"

【讨论】:

  • 非常好!一个小建议:当您将字符串分解为字符以提供Enumerable 方法时,例如map,使用each_char,它返回一个Enumerator,而不是chars,它返回一个(临时)数组. zipArray 方法,所以你必须使用chars
  • 或者,(str.each_char.map(&amp;:to_i).each_cons(2).map do |p,q| "#{p}#{ [p,q].any?(&amp;:odd?) ? ' - ' : ' ' }"; end &lt;&lt; str[-1]).join #=&gt; "9 - 5 - 6 0 - 1 - 1 - 3 - 7"
【解决方案3】:

这里有两种方法,用于:

str = "95601137"

使用枚举器

使用此方法,您将使用String#each_char 创建一个枚举器,您将向其发送方法Enumerator#nextEnumerator#peek

enum = str.each_char

s = ''
loop do
  c = enum.next
  s << c
  n = enum.peek
  s << ((c.to_i.odd? || n.to_i.odd?) ? ' - ' : ' ')
end
s #=> "9 - 5 - 6 0 - 1 - 1 - 3 - 7"

这里的关键是,当枚举器位于最后一个元素时('7'peek 会引发StopIteration 异常。异常由Kernel#loop 通过跳出循环来处理。

使用String#gsub

我们可以使用gsub 三次,每次用一个正则表达式,来:

  • 将破折号放在正确的位置
  • 短划线周围的空格
  • 偶数位数之间的空格

r = /       
    (\A\d) # match beginning of string followed by a digit, save in group 1
    |      # or
    (\d\z) # match a digit followed by end of string, save in group 2
    |      # or
    (\d)   # match a digit, save in capture group 3
    /x     # extended mode

str = "95601137"

str.gsub(r) do |s|
  if $1
    $1.to_i.odd? ? "#{$1}-"  : $1
  elsif $2
    $2.to_i.odd? ? "-#{$2}"  : $2 
  elsif $3
    $3.to_i.odd? ? "-#{$3}-" : $3
  else
    raise ArgumentError, "'#{s}' is not a digit" 
  end
end.gsub(/-+/, ' - ').gsub(/(\d)(\d)/,'\1 \2')
  #=> "9 - 5 - 6 0 - 1 - 1 - 3 - 7"

【讨论】:

  • 谢谢,Cary,这很有趣!您的枚举器实现启发了我each_cons(2) + zip 也可以工作的想法。谢谢!
  • Alexey,这将是一个相当优雅的解决方案。我建议你发布一个答案。
【解决方案4】:

替换:

answer = gets

与:

answer = gets.strip

然后,您将获得正确的输入输出:9

因为,当您输入9 并点击enter 时,您的输入实际上是:"9\n",其长度为2。这就是它打印9- 的原因。 使用:gets.strip 你只需 strip\n

要删除最后一个-(如果有),您可以使用chomp

final_result = final.join('').chomp('-')

并且,要删除第一个 -(如果有),您可以使用以下逻辑:

   if final_result[0] == '-'
    final_result[1..-1]
   else
    final_result
   end

这是代码的完整工作版本(尽可能多地保留您的代码):

def dashes(number)
    string = number.to_s

    i = 0

    final = []

    while i < string.length

        digit = string[i].to_i

        if ((digit)%2 != 0) && (i==0) && (string.length == 1) && ((string.length - 1) == 0)             
            final.push(string[i])
        elsif ((digit)%2 != 0) && (i==0) && (string.length != 1) && ((string.length - 1) > 0)               
            final.push(string[i] + "-")
        elsif ((digit)%2 != 0) && (i>0) && (i!=(string.length - 1)) && ((string.length != 1))               
            final.push("-" + string[i] + "-")
        elsif ((digit)%2 != 0) && (i!=0) && (i==(string.length - 1))                
            final.push("-" + string[i])
        else 
            final.push(string[i])
        end

    i += 1

    end

   final_result = final.join('').gsub('--', '-').chomp('-')
   puts "final_result: #{final_result.inspect}"

   if final_result[0] == '-'
    final_result[1..-1]
   else
    final_result
   end
end

puts("Give me any number.")

answer = gets.strip

puts dashes(answer)

# > Give me any number.
# > 95601137
# > "9-5-60-1-1-3-7"

【讨论】:

  • 不客气,欢迎来到stackoverflow。您总是可以接受您问题的最佳答案,也可以对您喜欢并认为有帮助的其他答案进行投票。要了解接受答案的工作原理,请参阅此帖子:meta.stackexchange.com/questions/5234/…
【解决方案5】:

一个幼稚的实现,可能有一些更聪明的方法来做到这一点:

def dashes(number)
  number                              # => 95601137
    .to_s                             # => "95601137"
    .chars                            # => ["9", "5", "6", "0", "1", "1", "3", "7"]
    .map(&:to_i)                      # => [9, 5, 6, 0, 1, 1, 3, 7]
    .map {|i| i.odd? ? "-#{i}-" : i } # => ["-9-", "-5-", 6, 0, "-1-", "-1-", "-3-", "-7-"]
    .join                             # => "-9--5-60-1--1--3--7-"
    .gsub(/^-|-$/, '')                # => "9--5-60-1--1--3--7"
    .gsub('--', '-')                  # => "9-5-60-1-1-3-7"
end

【讨论】:

    猜你喜欢
    • 2014-07-26
    • 2011-03-31
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 2023-02-13
    • 1970-01-01
    • 2017-05-12
    • 2012-05-19
    相关资源
    最近更新 更多