检查数字是否在整数内(ruby)

时间:2010-05-11 04:54:25

标签: ruby

中国人不喜欢数字4的数字。我将实施一个会员计划,其会员编号不包括数字4,例如:

number = 3
number.next.has4?
=> true

如何(有效地)完成has4?方法?

**编辑

感谢您的回答,我进行了简单的基准测试作为参考:

    class Fixnum
      def has4a?
        String(self).index('4') != nil
      end
    end

    class Fixnum
      def has4b?
        self.to_s[/4/]
      end
    end

    number = 3

    puts Time.now

    n = 0
    while n < 1000000
       number.next.has4a?
       n += 1
    end

    puts Time.now

    n = 0
    while n < 1000000
       number.next.has4b?
       n += 1
    end

    puts Time.now

我的电脑上的结果显示indexregex

> ruby has4.rb
Tue May 11 18:36:04 +0800 2010
Tue May 11 18:36:05 +0800 2010
Tue May 11 18:36:11 +0800 2010

以下编辑包含所有4种解决方案,并且可以轻松查看每种解决方案的持续时间:

class Fixnum
  def has4a?
    String(self).index('4') != nil
  end
end

class Fixnum
  def has4b?
    self.to_s[/4/]
  end
end

class Fixnum
  def has4c?
    temp = self
    while temp > 0
        if (temp % 10) == 4
            return true 
        end
        temp /= 10
    end
    false 
  end
end

class Fixnum
  def digits
    d, m = divmod(10)
    d > 0 ? d.digits + [m] : [m]
  end

  def has4d?
    self.digits.member?(4)
  end
end

before_A = Time.now

n = 0
has4 = 0
no4 = 0
while n < 5000000
   has4 += 1 if n.has4a? 
   no4  += 1 if !n.has4a?
   n    += 1
end

after_A = Time.now

puts after_A, has4, no4
puts "A duration: " + (after_A - before_A).to_s

before_B = Time.now

n = 0
has4 = 0
no4 = 0
while n < 5000000
   has4 += 1 if n.has4b? 
   no4  += 1 if !n.has4b?
   n    += 1
end

after_B = Time.now

puts after_B, has4, no4
puts "B duration: " + (after_B - before_B).to_s

before_C = Time.now

n = 0
has4 = 0
no4 = 0
while n < 5000000
   has4 += 1 if n.has4c? 
   no4  += 1 if !n.has4c?
   n    += 1
end

after_C = Time.now

puts after_C, has4, no4
puts "C duration: " + (after_C - before_C).to_s

before_D = Time.now

n = 0
has4 = 0
no4 = 0
while n < 5000000
   has4 += 1 if n.has4d? 
   no4  += 1 if !n.has4d?
   n    += 1
end

after_D = Time.now

puts after_D, has4, no4
puts "D duration: " + (after_D - before_D).to_s

结果(关于Karmic的ruby 1.8.7(2009-06-12 patchlevel 174)[i486-linux])。随意从其他机器发布数据。

Tue May 11 16:25:38 -0400 2010
2874236
2125764
A duration: 35.375095
Tue May 11 16:26:19 -0400 2010
2874236
2125764
B duration: 40.659878
Tue May 11 16:27:38 -0400 2010
2874236
2125764
C duration: 79.12419
Tue May 11 16:31:28 -0400 2010
2874236
2125764
D duration: 229.573483

对不起我之前的错字并感谢Matthew Flaschen修复它。这是我的基准:

    >ruby has4.rb
    Wed May 12 09:14:25 +0800 2010
    2874236
    2125764
    A duration: 18.186685
    Wed May 12 09:15:06 +0800 2010
    2874236
    2125764
    B duration: 40.388816
    Wed May 12 09:15:38 +0800 2010
    2874236
    2125764
    C duration: 32.639162
    Wed May 12 09:18:08 +0800 2010
    2874236
    2125764
    D duration: 150.024529

    >ruby -v
    ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mingw32]

6 个答案:

答案 0 :(得分:7)

class Fixnum
  def has4?
    String(self).index('4') != nil
  end
end

答案 1 :(得分:6)

如果您想在不将数字转换为字符串的情况下以数学方式执行此操作,则以下算法将起作用:

while num > 0
    if (num % 10) == 4
        return true
    num = num / 10
return false 

答案 2 :(得分:3)

类似

def has4?
  self.to_s[/4/]
end

答案 3 :(得分:1)

如果您不喜欢字符串,但喜欢递归:

class Fixnum
  def digits
    d, m = divmod(10)
    d > 0 ? d.digits + [m] : [m]
  end
end

12093.digits
#=> [1, 2, 0, 9, 3]
1.digits
#=> [1]
115.digits.member?(4)
#=> false
145.digits.member?(4)
#=> true

:)

答案 4 :(得分:1)

这是一个不同的解决方案:为内部ID使用简单的单向计数器。然后,当你想向用户显示他们的id#时,在基数9中渲染它,将所有4s交换为9s。

user_visible_id = internal_id.to_s(9).gsub('4','9').to_i

然后,在处理他们的信息时,您可以轻松地获取他们的内部ID:

internal_id = user_visible_id.to_s.gsub('9', '4').to_i(9)

这样生成内部ID很容易(您不必循环生成并检查它们,直到您得到一个没有4)。如果你愿意,你可以将oneup计数器包装在一个模块中,这样你的应用程序的其余部分就会使用user_visible_id,这将减少混乱:

module IDGen
  @counter = 0
  def self.next
    @counter += 1
    @counter.to_s(9).gsub('4','9').to_i
  end
  def self.reset
    @counter = 0
  end
end

#...
User.new( IDGen.next )

答案 5 :(得分:0)

numbers.select{|number|!number.include?('4')}