2010-05-11 2 views
2

Китайцам не нравятся цифры с цифрой 4. Я собираюсь реализовать программу членства с числом членов, не считая цифру 4, говорят:Чтобы проверить, находится ли цифра внутри целого числа (рубин)

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

как метод has4? может быть сделано (эффективно)?

** EDIT

Спасибо за ответы, я выполнил простой бенчмаркинга в качестве ссылки:

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 

результат (ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux] on Karmic). Не стесняйтесь размещать данные с других компьютеров.

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 

Извините за мою предыдущую опечатку и спасибо Мэтью Флашен за ее исправление. вот мой тест:

>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] 
+2

Hahah какой веселая причиной реализации. –

+1

Да, это потому, что произношение 四 (четыре) похоже на 死 (мертвое) по-китайски ;-) – ohho

+1

Я так и не понял. Тоны разные. –

ответ

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

Нелепо неэффективно использовать строковые манипуляции для числовой проблемы. –

+1

@ Педро, эффективность человека имеет первостепенное значение. Только тогда, когда код окажется недостаточно быстрым, если потребности машины имеют приоритет. –

+0

@Pedro. Моя версия быстрее всего представлена ​​в тесте OP (после того, как он исправил ее для вызова другого метода каждый цикл, а не 'a' каждый раз). Это не удивительно, так как индекс и преобразование в строку являются очень распространенными и, следовательно, сильно оптимизированы. В следующий раз, когда вы начнете предъявлять требования к производительности. –

3

что-то вроде

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

?

+0

преобразование числа в строку и создание автомата с регулярным выражением чудесно эффективно! (ирония) –

+0

'self.' можно оставить без изменений, если хотите. –

6

Если вы хотите сделать это математически без преобразования числа в строку, следующий алгоритм будет работать:

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

это выглядит как python для меня ;-) – ohho

+1

+1 наиболее эффективное решение. Когда я прочитал струнные решения, я почувствовал, как в моих глазах горит ожог. http://stackoverflow.com/questions/2349378/new-programming-jargon-you-coined/2444303#2444303 – wilhelmtell

+0

Вот как это должно быть сделано. –

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 

:)

1

Это другое решение: используйте простой счетчик для ваших внутренних идентификаторов. Затем, когда вы хотите показать пользователю свой идентификатор #, сделайте его в базе 9, заменив все 4s на 9 секунд.

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

Затем, при обработке их информации, вы можете получить свой внутренний идентификатор обратно так же легко:

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

Этот способ генерации внутренних идентификаторов легко (вы не должны перебрать генерации и проверяя их, пока вы не получите один без 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) 
+0

Мне это нравится, за исключением того, что идентификатор, видимый пользователем, всегда обрабатывается как строка. Таким образом, это будет 'user_visible_id = internal_id.to_s (9) .gsub ('4', '9')' и 'internal_id = user_visible_id.gsub ('9', '4'). To_i (9)' –

Смежные вопросы