为什么我的代码只选择等于10的年份?

时间:2013-09-20 07:55:28

标签: ruby-on-rails ruby ruby-on-rails-3

我是编程的初学者,并且遇到了这个if语句的问题:

if (f.year == (10 || 20 || 30 || 40 || 50 || 60 || 70 || 80 || 90 || 100 || 110 || 120)) && (f.rund != true)

第一个问题是这段代码非常复杂。实际上我只想检查f.year是否是一个两位数的圆形数字。

接下来我的代码无法正常运行。不知何故,它只选择等于f.year的{​​{1}}。

我该如何解决这些问题?

7 个答案:

答案 0 :(得分:4)

这是因为

(10 || 20 || 30 || 40 || 50 || 60 || 70 || 80 || 90 || 100 || 110 || 120)

表达式始终计算为10

您可以使用例如:

解决问题
(1..12).map { |el| el * 10 }.include?(f.year)

或者,正如@AurpRakshit所建议的那样:

(1..12).map(&10.method(:*)).include?(f.year)

Here你有更多生成这种数组的例子。

或者,如果您真的想检查f.year是否为两位数字,您可以:

(10...100).include?(f.year) && f.year % 1 == 0

答案 1 :(得分:4)

您可以使用Range#stepNumeric#step

(10..120).step(10).to_a  #=> [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]

10.step(120, 10).to_a    #=> [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]

并致电Enumerable#include?

(10..120).step(10).include? year

10.step(120, 10).include? year

答案 2 :(得分:2)

要回答您的第一点,代码应为:

if (f.year == 10 || f.year == 20 || f.year == 30 ...

您的表达式f.year == (10 || 20 || 30 ...不起作用,因为它由ruby评估如下:

  • 括号强制10 || 20 || 30 ...首先评估
  • ||运算符返回其左操作数(如果为true),否则返回其右操作数
  • Ruby会将非nilfalse的任何内容视为“true”,因此表达式10 || 20 || 30 ...的计算结果为10
  • 所以你的表达归结为(f.year == 10) && (f.rund != true)

答案 3 :(得分:2)

您已经被告知为什么您的代码无法正常工作,我只是建议在这里使用数学方法而不是使用include?,您的条件可以写成:

if f.year.modulo(10).zero? && f.year.between?(10, 120) && !f.rund
  ...

它可能稍微不那么清楚但速度要快得多。


更新

此解决方案的缺点是当f.year不是Numeric对象时失败:

nil.modulo(10)
# NoMethodError: ...

虽然:

[10].include?(nil)
# => false

基准测试:

require 'fruity'

a = (1..10000)

compare do   
  map_include do
    a.each do |i|
      (1..12).map(&10.method(:*)).include?(i)
    end
  end

  step_include do
    a.each do |i|
      (10..120).step(10).include?(i)
    end
  end

  divmod_include do
    a.each do |i|
      q, r = i.divmod(10); (1..12).include?(q) && r.zero?
    end
  end

  math do
    a.each do |i|
      i.modulo(10).zero? && i.between?(10, 120)
    end
  end      
end
Running each test once. Test will take about 2 seconds.
math is faster than divmod_include by 1.9x ± 0.01
divmod_include is faster than step_include by 9x ± 0.1
step_include is faster than map_include by 3.4x ± 0.1

答案 4 :(得分:1)

我不确定你的问题,但第一个条件可以写成

q, r = f.year.divmod(10); (1..12).include?(q) && r.zero?

[10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120].include?(f.year)

答案 5 :(得分:1)

很难说OP想要什么,但......

require 'fruity'

ARY = (1..1000).to_a

compare do
  test_mod_and_le do
    ARY.each do |i|
      (i % 10 == 0) && (i <= 120)
    end
  end

  test_mod_and_range do
    ARY.each do |i|
      (i % 10 == 0) && ((10..120) === i)
    end
  end

  test_case_when do
    ARY.each do |i|
      case i
      when 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120
        true
      else
        false
      end
    end
  end

  map_include do
    ARY.each do |i|
      (1..12).map(&10.method(:*)).include?(i)
    end
  end

  step_include do
    ARY.each do |i|
      (10..120).step(10).include?(i)
    end
  end

  divmod_include do
    ARY.each do |i|
      q, r = i.divmod(10); (1..12).include?(q) && r.zero?
    end
  end

  math do
    ARY.each do |i|
      i.modulo(10).zero? && i.between?(10, 120)
    end
  end      
end

哪个输出:

Running each test 32 times. Test will take about 4 seconds.
test_case_when is similar to test_mod_and_le
test_mod_and_le is faster than test_mod_and_range by 19.999999999999996% ± 10.0%
test_mod_and_range is faster than math by 50.0% ± 10.0%
math is faster than divmod_include by 80.0% ± 10.0%
divmod_include is faster than step_include by 5.9x ± 0.1
step_include is faster than map_include by 2.9x ± 0.1

答案 6 :(得分:0)

条件不起作用。括号内与OR相关联的所有数字都会在检查与f.year的相等性之前进行评估。

这里的大多数答案似乎过于复杂。您可以使用基本数学来解决您的问题:

if year % 10 == 0 && year.to_s.size == 2
   # do stuff
end

在此示例中,模运算符%在除以10时返回余数。如果余数为0,则它​​是10的倍数。您可以使用任何数字。 Modulo 2会检查数字是否均匀。

第二部分检查位数。它首先使用to_s将其转换为字符串,然后检查它的长度,基本上是多少个字符。将10转换为字符串会产生'10',其中包含2个字符。

您的问题似乎有点不清楚。您想要在代码示例中包含数字100,110和120吗?或者您只想要两个数字,如文中所述?