中国人不喜欢数字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
我的电脑上的结果显示index
比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
以下编辑包含所有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]
答案 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')}