Чтобы проверить, находится ли цифра внутри целого числа (ruby) - PullRequest
2 голосов
/ 11 мая 2010

Китайцы не любят цифры с цифрой 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

результат (ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux] на 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]

Ответы [ 6 ]

7 голосов
/ 11 мая 2010
class Fixnum
  def has4?
    String(self).index('4') != nil
  end
end
6 голосов
/ 11 мая 2010

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

while num > 0
    if (num % 10) == 4
        return true
    num = num / 10
return false 
3 голосов
/ 11 мая 2010

что-то вроде

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

1 голос
/ 11 мая 2010

Вот другое решение: используйте простой счетчик для внутренних идентификаторов. Затем, когда вы захотите показать пользователю его id #, отобразите его в базе 9, меняя все 4 на 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 )
1 голос
/ 11 мая 2010

Если вам не нравятся строки, но вам нравится рекурсия:

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

:)

0 голосов
/ 09 октября 2014
numbers.select{|number|!number.include?('4')}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...