Рефакторинг этого метода в один лайнер - PullRequest
1 голос
/ 19 марта 2020

Простой код для поиска идеального квадрата

def perfect_square(num)
  (1..num).each {|n| return true if n*n == num }
  false    
end``

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

Ответы [ 6 ]

2 голосов
/ 19 марта 2020

Поскольку произведение идеальных квадратов является идеальным квадратом, используется Prime # prime_division :

require 'prime'

def perfect_square?(n)
  n.prime_division.all? { |_, exp| exp % 2 == 0 }
end
1 голос
/ 21 марта 2020

Я подумал, что было бы интересно сравнить различные методы. Есть сюрпризы?

require 'benchmark'
require 'prime'

def duckets(num)
  (1..1+num/2).each {|n| return true if n*n == num }
  false    
end

def steenslag(num)
  Integer.sqrt(num)**2 == num
end

def iGian(num)
  num.prime_division.all? { |_, exp| exp % 2 == 0 }
end

def cary(num)
  (1..1+num/2).bsearch { |n| n*n >= num }**2 == num
end

def test(arr, meth)
  arr.map { |num| method(meth).call(num) }
end

Этот метод сопоставляет каждый элемент arr с true если это идеальный квадрат (иначе false), используя метод meth (символ).

def benchem(arr)
  Benchmark.bm do |x|
    x.report("enumerate")      { test(arr, :duckets)   }
    x.report("integer_sqrt")   { test(arr, :steenslag) }
    x.report("prime_divisors") { test(arr, :iGian)     }
    x.report("bsearch")        { test(arr, :cary)      }
  end
end

benchem([*2..100])
    user           system     total       real
  enumerate       0.000244   0.000000   0.000244 (  0.000229)  #3
  integer_sqrt    0.000049   0.000000   0.000049 (  0.000048)  #1
  prime_divisors  0.000963   0.000000   0.000963 (  0.000967)  #4
  bsearch         0.000086   0.000000   0.000086 (  0.000086)  #2

benchem([*101..1000])
    user           system     total       real
  enumerate       0.018636   0.000000   0.018636 (  0.018662)  #4
  integer_sqrt    0.000252   0.000000   0.000252 (  0.000255)  #1
  prime_divisors  0.003402   0.000000   0.003402 (  0.003407)  #3
  bsearch         0.000870   0.000000   0.000870 (  0.000872)  #2

benchem([*1001..10000])
    user           system     total       real
  enumerate       1.345501   0.000000   1.345501 (  1.345650)  #4 
  integer_sqrt    0.004647   0.000000   0.004647 (  0.004655)  #1
  prime_divisors  0.048204   0.000000   0.048204 (  0.048226)  #3
  bsearch         0.010349   0.000000   0.010349 (  0.010362)  #2

benchem([*10001..100000])
    user           system     total      real
  enumerate     147.814253   0.000000 147.814253 (147.833672)  #4
  integer_sqrt    0.036118   0.000000   0.036118 (  0.036115)  #1
  prime_divisors  0.889245   0.000000   0.889245 (  0.889367)  #3
  bsearch         0.127438   0.000000   0.127438 (  0.127459)  #2
1 голос
/ 19 марта 2020

Для забавы, вот еще один способ:

def perfect_square(num)
  (1..1+num/2).find { |n| n*n >= num }**2 == num
end

(1..200).select { |num| perfect_square(num) }
  #=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196]

Для большей эффективности рабочую линию можно заменить на

  (1..1+num/2).bsearch { |n| n*n >= num }**2 == num

См. Array # bsearch .

1 голос
/ 19 марта 2020

Ruby имеет целое число :: sqrt с версии 2.5

def perfect_square(num)
  Integer.sqrt(num)**2 == num
end
1 голос
/ 19 марта 2020

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

def perfect_square(num) (1..num).each {|n| return true if n*n == num }; false end
0 голосов
/ 19 марта 2020

Вы можете сделать это вместо этого

def perfect_square(num)
  !(1..num).find { |n| n * n == num }.nil?    
end

Найдите любое число от 1 до num, которое имеет квадрат num, проверьте, не ноль ли оно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...