【问题标题】:foo bar not printing the correct outputfoo bar 没有打印正确的输出
【发布时间】:2017-10-25 10:46:32
【问题描述】:

目前我的代码将显示 1 到 100,但当它可以被 3 或 5 或两者整除时,实际上不会打印出 case 语句......我在这里做错了什么?

def display(item_count)
  n = 1  
  while n <= item_count
    case n
    when n % 3 == 0 
      puts "foo"
    when n % 5 == 0
      puts "bar"
    when (n % 3 ==0 && n % 5 == 0) 
      puts "foobar"
    else
      puts "#{n}"
    end #--  case end stmt
    n = n + 1
  end #while end statement
end #end satement for metod

puts " How many items do you want to see"
item_count = gets.chomp.to_i
puts "#{display(item_count)}"

【问题讨论】:

  • foobar 问题的确切目的是检测/排除编写此类代码的人。确实,问题正在按预期运行。
  • 目前我的代码将显示 1 到 100,但当它可以被 3 或 5 或两者整除时,实际上不会打印出 case 语句......我在这里做错了什么?
  • 阅读 Ruby 中的 case expressions,直到你明白为什么发布的代码总是采用 else 分支。
  • @axiac ...好的,我明白我做错了什么..这是新的实现:def display(item_count) n = 1 while n
  • 这被称为 fizzbuzz。

标签: ruby fizzbuzz


【解决方案1】:

您可以在 ruby​​ 中使用不带参数的 case 语句。 when 子句仍然必须返回 true 或 false。

case
when true
  puts 'this happens'
when false
  puts 'this does not happen'
end

因此,如果您只是更改原始帖子中的代码(至少是 case 语句)

case n

进入

case

并将“foobar”测试移动到“when”列表的顶部。我的另一个答案也使用了这种结构,但消除了堆栈操作并产生了一个可存储/可传输的对象,而不仅仅是显示结果。

注意:调用零?对象上的方法比将其与文字 0 进行比较要快。(x.zero? 比 x == 0 快)。

【讨论】:

  • “必须仍然返回真或假” - 不完全是。只是真/假,就像在大多数红宝石中一样。
  • 你是对的,这是一个重要的区别。
【解决方案2】:

case expression 使用=== 将您提供的参数与每个when 表达式进行比较(在大多数情况下与== 相同)。所以你的代码大致相当于

if (n % 3 == 0) === n
  puts "foo"
elsif (n % 5 == 0) === n
  puts "bar"
elsif (n % 3 == 0 && n % 5 == 0) === n
  puts "foobar"
else
  puts "#{n}"
end

所有when 表达式都返回truefalse,所以每个case 都失败了,你最终会得到else。只需使用这种if 格式而不是case,您就可以做您想做的事(尽管您需要重新安排您的条件以获得正确的输出)。

【讨论】:

  • @SergioTulentsev 如果您真的阅读了我的回答,我并不是要发布一个完整的工作解决方案。我正在向 OP 展示他的代码实际执行的逻辑。 :)
  • 啊,对不起,我的错 :)
【解决方案3】:
print "Enter amount of times> "
(1..gets.to_i).each do |i|
  puts(
    "".tap do |res|
      res << "foo" if (i % 3).zero?
      res << "bar" if (i % 5).zero?
      res << i.to_s if res.empty?
    end)
end

【讨论】:

  • 非常实用,可读性差。 :) 让我们看看我能不能想出一个更好的 sn-p。
  • Extensible 解决方案。虽然更不可读。 ://
  • @SergioTulentsev 我在第一个版本中就是这样,但后来我认为循环 2 个元素没有任何意义:) 当然,case 是一种方法。
  • 我以为我有一个beginning of a smart-ass solution,但不知道如何将它与.grep 一起使用(以一种非常干净的方式)。哦,好吧...
  • @SergioTulentsev 像这样:(1..gets.to_i).map { |i| filters.map { |f, v| v if f === i }.join.tap { |e| e &lt;&lt; i.to_s if e.empty? } }?使用filters.map.compact 的临时局部变量可能会更短,但我讨厌局部变量。
【解决方案4】:

展示东西是一回事;将功能的结果保存在内存中以供进一步使用,例如通过网络连接或存储进行传输,是另一回事。在 ruby​​ 中,一切都是对象,因此您应该对对象进行操作。这就是红宝石的用途。

编辑以解决多次循环和可读性问题。

我的原件被谴责为不可读,然后有人想出了一个使用 lambda 文字和猴子补丁的单子解决方案。即使是经验丰富的程序员也将面临遵循其逻辑的挑战,并且解释器中涉及的堆栈操作无论如何都会将可伸缩性抛到窗外。单个循环中的程序块解决了所有这些问题,而不是迂腐。 “可读”也意味着“可以理解”。

在 ruby​​ >= 2.4 中不需要冻结字符串文字;它们应该被自动冻结,但由于单循环解决方案是为了解决可伸缩性(想象一下调用它一百万次),因此不应忽视这种优化。此外,我已将其简化为块内的单个条件语句,这意味着更大的可扩展性。

print 'How many items do you want to see: '.freeze

list = (1..gets.to_i).collect do |i|
  div_by_3 = (i % 3).zero?
  div_by_5 = (i % 5).zero?
  case 
    when div_by_3 && div_by_5
      :foobar
    when div_by_3
      :foo
    when div_by_5
      :bar
    else
     i
  end
end

puts list.to_s

输出:

How many items do you want to see: 50
[1, 2, :foo, 4, :bar, :foo, 7, 8, :foo, :bar, 11, :foo, 13, 14, :foobar, 16, 17, :foo, 19, :bar, :foo, 22, 23, :foo, :bar, 26, :foo, 28, 29, :foobar, 31, 32, :foo, 34, :bar, :foo, 37, 38, :foo, :bar, 41, :foo, 43, 44, :foobar, 46, 47, :foo, 49, :bar]

【讨论】:

  • 无论如何,这不是红宝石方式。三个后续循环而不是唯一需要的一个循环会立即将该代码从可接受的范围中剔除。
  • 现实世界并非如此;您的反对在可扩展性范围之外是迂腐的。与程序员时间相比,硅便宜。如果可伸缩性是首要考虑的问题,实际上你可以用一个 map.with_index 做同样的事情,但它会很难看。 Ruby 代码最常用于通过网络传输结果,或转换存储的数据并再次存储。为此,您必须将结果放入数据结构中。
  • 这段代码也是完全不可读的(阅读:这是一个完美的例子,说明一个人永远不应该写 ruby​​。)就地变异列表,三个不必要的三元组,冗余检查:所有的气味。
  • 旁注:您不需要在初始行中使用to_a,范围也是可迭代的。
  • 虽然我的措辞不同,但我必须同意 mudasobwa。这不是惯用的红宝石的样子。在本主题的所有 sn-ps 中,问题中的那个最接近 ruby​​ 方式(显然需要一些修复。就像将打印与计算分开)
猜你喜欢
  • 1970-01-01
  • 2018-08-22
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 2017-09-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多