Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

To check whether a digit is inside an integer (ruby)

Tags:

ruby

Chinese people do not like numbers with a digit 4 in it. I am going to implement a membership program with membership numbers not including the digit 4, say:

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

how the has4? method can be done (efficiently)?

** EDIT

Thanks for the answers, I performed simple benchmarking as a reference:

    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

the result on my PC shows index is faster than regex:

> 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

Edited below to include all 4 solutions, and make it easy to see duration of each:

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

result (ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux] on Karmic). Feel free to post data from other machines.

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

sorry for my previous typo and thanks Matthew Flaschen for fixing it. here's my benchmark:

    >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]
like image 883
ohho Avatar asked Jun 24 '26 10:06

ohho


2 Answers

class Fixnum
  def has4?
    String(self).index('4') != nil
  end
end
like image 124
Matthew Flaschen Avatar answered Jun 26 '26 04:06

Matthew Flaschen


If you want to do this mathematically without converting the number to a string, the following algorithm will work:

while num > 0
    if (num % 10) == 4
        return true
    num = num / 10
return false 
like image 39
R Samuel Klatchko Avatar answered Jun 26 '26 02:06

R Samuel Klatchko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!