Как сделать этот блок кода python коротким и эффективным

Я новичок в программировании и питоне. Я решал проблему. Я нашел решение, но оно кажется слишком медленным.

    if n % 2 == 0 and n % 3 == 0 and\
       n % 4 == 0 and n % 5 == 0 and\
       n % 6 == 0 and n % 7 == 0 and\
       n % 8 == 0 and n % 9 == 0 and\
       n % 10 == 0 and n % 11 == 0 and\
       n % 12 == 0 and n % 13 == 0 and\
       n % 14 == 0 and n % 15 == 0 and\
       n % 16 == 0 and n % 17 == 0 and\
       n % 18 == 0 and n % 19 == 0 and\
       n % 20 == 0:

Это часть кода для проверки того, делится ли n на все числа от 2 до 20 или нет.

Как я могу сделать это коротким и эффективным.

Ответ 1

Там более умный способ сделать это. Если n делится на каждое целое число в диапазоне (1, 21), то оно должно быть кратным наименьшее общее число этих целых чисел,

Вы можете вычислить LCM набора чисел постепенно, используя GCD (наибольший общий делитель). Вы можете импортировать функцию gcd из модуля fractions или реализовать ее непосредственно в вашем коде.

def gcd(a, b):
    ''' Greatest Common Divisor '''
    while b:
        a, b = b, a % b
    return a

def lcm(a, b):
    ''' Least Common Multiple '''
    return a * b // gcd(a, b)

# Compute the LCM of range(1, 21)
n = 2
for i in range(3, 21):
    n = lcm(n, i)

lcm20 = n
print('LCM =', lcm20)
#test 
for i in range(1, 21):
    print(i, lcm20 % i)

Выход

LCM = 232792560
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
13 0
14 0
15 0
16 0
17 0
18 0
19 0
20 0

Теперь, чтобы проверить, если любое число n делится на все числа, это диапазон (1, 21), вы можете просто сделать

n % lcm20 == 0

или скопируйте константу в свой script:

# 232792560 is the LCM of 1..20
n % 232792560 == 0

Как отмечает Антон Шервуд в своем комментарии, мы можем ускорить процесс поиска требуемого LCM, просто взяв LCM в верхней половине диапазона. Это работает, потому что каждое число в нижней половине диапазона является делителем числа в верхней половине диапазона.

Мы можем улучшить скорость еще больше, объединив вычисления GCD и LCM, а не вызывающие функции для выполнения этих операций. Вызов функций Python заметно медленнее вызовов функций C из-за дополнительных накладных расходов.

Якк упоминает альтернативный подход к поиску требуемого LCM: вычислить произведение главных степеней в диапазоне. Это довольно быстро, если диапазон достаточно большой (около 40 или около того), но для небольших чисел простой цикл LCM выполняется быстрее.

Ниже приведен код timeit, который сравнивает скорость этих различных подходов. Этот script работает на Python 2 и 3, я тестировал его на Python 2.6 и Python 3.6. Он использует функцию главного списка Роберта Уильяма Хэнкса для реализации предложения Якка. Я немного изменил код Роберта, чтобы сделать его совместимым с Python 3. Я полагаю, что может быть более эффективный способ найти основные полномочия; если так, я бы хотел это увидеть.:)

Ранее я упоминал, что в модуле fractions есть функция GCD. Я провел с ним несколько тестов времени, но это заметно медленнее, чем мой код. Предположительно, потому что он выполняет проверку ошибок в аргументах.

#!/usr/bin/env python3

''' Least Common Multiple of the numbers in range(1, m)

    Speed tests

    Written by PM 2Ring 2016.08.04
'''


from __future__ import print_function
from timeit import Timer
#from fractions import gcd

def gcd(a, b):
    ''' Greatest Common Divisor '''
    while b:
        a, b = b, a % b
    return a

def lcm(a, b):
    ''' Least Common Multiple '''
    return a * b // gcd(a, b)

def primes(n):
    ''' Returns a list of primes < n '''
    # By Robert William Hanks, from https://stackoverflow.com/a/3035188/4014959
    sieve = [True] * (n//2)
    for i in range(3, int(n ** 0.5) + 1, 2):
        if sieve[i//2]:
            sieve[i*i//2::i] = [False] * ((n - i*i - 1) // (2*i) + 1)
    return [2] + [2*i + 1 for i in range(1, n//2) if sieve[i]]

def lcm_range_PM(m):
    ''' The LCM of range(1, m) '''
    n = 1
    for i in range(2, m):
        n = lcm(n, i)
    return n

def lcm_range_AS(m):
    ''' The LCM of range(1, m) '''
    n = m // 2
    for i in range(n + 1, m):
        n = lcm(n, i)
    return n

def lcm_range_fast(m):
    ''' The LCM of range(1, m) '''
    n = m // 2
    for i in range(n + 1, m):
        a, b = n, i
        while b:
            a, b = b, a % b
        n = n * i // a
    return n

def lcm_range_primes(m):
    n = 1
    for p in primes(m):
        a = p
        while a < m:
            a *= p
        n *= a // p
    return n

funcs = (
    lcm_range_PM,
    lcm_range_AS,
    lcm_range_fast,
    lcm_range_primes
)

def verify(hi):
    ''' Verify that all the functions give the same result '''
    for i in range(2, hi + 1):
        a = [func(i) for func in funcs]
        a0 = a[0]
        assert all(u == a0 for u in a[1:]), (i, a)
    print('ok')

def time_test(loops, reps):
    ''' Print timing stats for all the functions '''
    timings = []
    for func in funcs:
        fname = func.__name__
        setup = 'from __main__ import num, ' + fname
        cmd = fname + '(num)'
        t = Timer(cmd, setup)
        result = t.repeat(reps, loops)
        result.sort()
        timings.append((result, fname))

    timings.sort()
    for result, fname in timings:
        print('{0:16} {1}'.format(fname, result))

verify(500)

reps = 3
loops = 8192
num = 2
for _ in range(10): 
    print('\nnum = {0}, loops = {1}'.format(num, loops))
    time_test(loops, reps)
    num *= 2
    loops //= 2

print('\n' + '- ' * 40)

funcs = (
    lcm_range_fast,
    lcm_range_primes
)

loops = 1000
for num in range(30, 60):
    print('\nnum = {0}, loops = {1}'.format(num, loops))
    time_test(loops, reps)

Выход

ok

num = 2, loops = 8192
lcm_range_PM     [0.013914467999711633, 0.01393848999941838, 0.023966414999449626]
lcm_range_fast   [0.01656803699916054, 0.016577592001340236, 0.016578077998929075]
lcm_range_AS     [0.01738608899904648, 0.017602848000024096, 0.01770572900022671]
lcm_range_primes [0.0979132459997345, 0.09863009199943917, 0.10133290699923236]

num = 4, loops = 4096
lcm_range_fast   [0.01580070299860381, 0.01581421999981103, 0.016406731001552544]
lcm_range_AS     [0.020135083001150633, 0.021132826999746612, 0.021589830999801052]
lcm_range_PM     [0.02821666900126729, 0.029041511999821523, 0.036708851001094445]
lcm_range_primes [0.06287289499960025, 0.06381634699937422, 0.06406087200048205]

num = 8, loops = 2048
lcm_range_fast   [0.015360695999333984, 0.02138442599971313, 0.02630166100061615]
lcm_range_AS     [0.02104746699842508, 0.021742354998423252, 0.022648989999652258]
lcm_range_PM     [0.03499621999981173, 0.03546843599906424, 0.042924503999529406]
lcm_range_primes [0.03741390599861916, 0.03865244000007806, 0.03959638999913295]

num = 16, loops = 1024
lcm_range_fast   [0.015973221999956877, 0.01600381199932599, 0.01603960700049356]
lcm_range_AS     [0.023003745000096387, 0.023848425998949097, 0.024875303000953863]
lcm_range_primes [0.028887982000014745, 0.029422679001072538, 0.029940758000520873]
lcm_range_PM     [0.03780223299872887, 0.03925949299991771, 0.04462484900068375]

num = 32, loops = 512
lcm_range_fast   [0.018606906000059098, 0.02557359899947187, 0.03725786200084258]
lcm_range_primes [0.021675119000065024, 0.022790905999499955, 0.03934840099827852]
lcm_range_AS     [0.025330593998660333, 0.02545427500081132, 0.026093265998497372]
lcm_range_PM     [0.044320442000753246, 0.044836185001258855, 0.05193238799984101]

num = 64, loops = 256
lcm_range_primes [0.01650579099987226, 0.02443148000020301, 0.033489004999864846]
lcm_range_fast   [0.018367127000601613, 0.019002625000211992, 0.01955779200034158]
lcm_range_AS     [0.026258470001266687, 0.04113643799973943, 0.0436801750001905]
lcm_range_PM     [0.04854909000096086, 0.054864030998942326, 0.0797669980001956]

num = 128, loops = 128
lcm_range_primes [0.013294352000229992, 0.013383581999732996, 0.024317635999977938]
lcm_range_fast   [0.02098568399924261, 0.02108044199849246, 0.03272008299973095]
lcm_range_AS     [0.028861763999884715, 0.0399744570004259, 0.04660961700028565]
lcm_range_PM     [0.05302166500041494, 0.059346372001527925, 0.07757829000001948]

num = 256, loops = 64
lcm_range_primes [0.010487794999789912, 0.010514846000660327, 0.01055656300013652]
lcm_range_fast   [0.02619308099929185, 0.02637610199963092, 0.03755473099954543]
lcm_range_AS     [0.03422451699952944, 0.03513622399987071, 0.05206341099983547]
lcm_range_PM     [0.06851765200008231, 0.073690847000762, 0.07841700100107118]

num = 512, loops = 32
lcm_range_primes [0.009275872000216623, 0.009292663999076467, 0.009309271999882185]
lcm_range_fast   [0.03759837500001595, 0.03774761099884927, 0.0383951439998782]
lcm_range_AS     [0.04527828100071929, 0.046646228000099654, 0.0569303670017689]
lcm_range_PM     [0.11064135100059502, 0.12738902800083451, 0.13843623499997193]

num = 1024, loops = 16
lcm_range_primes [0.009248070000467123, 0.00931658900117327, 0.010279963000357384]
lcm_range_fast   [0.05642254200029129, 0.05663530499987246, 0.05796714499956579]
lcm_range_AS     [0.06509247900066839, 0.0652738099997805, 0.0658949799999391]
lcm_range_PM     [0.11376448099872505, 0.11652833600055601, 0.12083648199950403]

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

num = 30, loops = 1000
lcm_range_fast   [0.03275446999941778, 0.033530079999763984, 0.04002811799909978]
lcm_range_primes [0.04062690899991139, 0.040886697999667376, 0.04130547800014028]

num = 31, loops = 1000
lcm_range_fast   [0.03423191600086284, 0.039976395999474335, 0.04078094900069118]
lcm_range_primes [0.04053011599899037, 0.04140578700025799, 0.04566663300101936]

num = 32, loops = 1000
lcm_range_fast   [0.036124262000157614, 0.036700047998238006, 0.04392546200142533]
lcm_range_primes [0.042666604998885305, 0.04393434200028423, 0.05142524700022477]

num = 33, loops = 1000
lcm_range_fast   [0.03875456000059785, 0.03997290300139866, 0.044469664000644116]
lcm_range_primes [0.04280027899949346, 0.0437891679994209, 0.04381238600035431]

num = 34, loops = 1000
lcm_range_fast   [0.038203157999305404, 0.03937257799952931, 0.04531203700025799]
lcm_range_primes [0.043273317998682614, 0.043349457999283914, 0.04420187600044301]

num = 35, loops = 1000
lcm_range_fast   [0.04228670399970724, 0.04346491300020716, 0.047442203998798504]
lcm_range_primes [0.04332462999991549, 0.0433610400014004, 0.04525857199951133]

num = 36, loops = 1000
lcm_range_fast   [0.04175829099949624, 0.04217126499861479, 0.046840714998324984]
lcm_range_primes [0.04339772299863398, 0.04360795700085873, 0.04453475599984813]

num = 37, loops = 1000
lcm_range_fast   [0.04231068799890636, 0.04373836499871686, 0.05010528200000408]
lcm_range_primes [0.04371378700125206, 0.04463105400100176, 0.04481986299833807]

num = 38, loops = 1000
lcm_range_fast   [0.042841554000915494, 0.043649038998410106, 0.04868016199907288]
lcm_range_primes [0.04571479200058093, 0.04654245399979118, 0.04671720700025617]

num = 39, loops = 1000
lcm_range_fast   [0.04469198100014182, 0.04786454099848925, 0.05639159299971652]
lcm_range_primes [0.04572433999965142, 0.04583652600013011, 0.046649005000290344]

num = 40, loops = 1000
lcm_range_fast   [0.044788433999201516, 0.046223339000789565, 0.05302252199908253]
lcm_range_primes [0.045482261000870494, 0.04680115900009696, 0.046941823999077315]

num = 41, loops = 1000
lcm_range_fast   [0.04650144500010356, 0.04783133000091766, 0.05405569400136301]
lcm_range_primes [0.04678159699869866, 0.046870936999766855, 0.04726529199979268]

num = 42, loops = 1000
lcm_range_fast   [0.04772527699969942, 0.04824955299955036, 0.05483534199993301]
lcm_range_primes [0.0478546140002436, 0.048954233001495595, 0.04905354400034412]

num = 43, loops = 1000
lcm_range_primes [0.047872637000182294, 0.048093739000250935, 0.048502418998396024]
lcm_range_fast   [0.04906317900167778, 0.05292572700091114, 0.09274570399975346]

num = 44, loops = 1000
lcm_range_primes [0.049750300000596326, 0.050272532000235515, 0.05087747600009607]
lcm_range_fast   [0.050906279000628274, 0.05109869400075695, 0.05820328499976313]

num = 45, loops = 1000
lcm_range_primes [0.050158660000306554, 0.050309066000409075, 0.054478109999763547]
lcm_range_fast   [0.05236714599959669, 0.0539534259987704, 0.058996140000090236]

num = 46, loops = 1000
lcm_range_primes [0.049894845999006066, 0.0512076260001777, 0.051318084999365965]
lcm_range_fast   [0.05081920200063905, 0.051397655999608105, 0.05722950699964713]

num = 47, loops = 1000
lcm_range_primes [0.04971165599999949, 0.05024208400027419, 0.051092388999677496]
lcm_range_fast   [0.05388393700013694, 0.05502788499870803, 0.05994341699988581]

num = 48, loops = 1000
lcm_range_primes [0.0517014939996443, 0.05279760400117084, 0.052917389999493025]
lcm_range_fast   [0.05402479099939228, 0.055251746000067214, 0.06128628700025729]

num = 49, loops = 1000
lcm_range_primes [0.05412415899991174, 0.05474224499994307, 0.05610057699959725]
lcm_range_fast   [0.05757830900074623, 0.0590323519991216, 0.06310263200066402]

num = 50, loops = 1000
lcm_range_primes [0.054892387001018506, 0.05504404100065585, 0.05610281799999939]
lcm_range_fast   [0.0588886920013465, 0.0594741389995761, 0.06682244199873821]

num = 51, loops = 1000
lcm_range_primes [0.05582956999933231, 0.055921465000210446, 0.06004790299994056]
lcm_range_fast   [0.060586288000195054, 0.061715600999377784, 0.06733965300009004]

num = 52, loops = 1000
lcm_range_primes [0.0557458109997242, 0.05669860099988, 0.056761407999147195]
lcm_range_fast   [0.060323355999571504, 0.06177857100010442, 0.06778404599936039]

num = 53, loops = 1000
lcm_range_primes [0.05501838899908762, 0.05541463699955784, 0.0561610999993718]
lcm_range_fast   [0.06281833000139159, 0.06334177999997337, 0.06843207200108736]

num = 54, loops = 1000
lcm_range_primes [0.057314272000439814, 0.059501444000488846, 0.060004871998899034]
lcm_range_fast   [0.06634221600143064, 0.06662889200015343, 0.07153233899953193]

num = 55, loops = 1000
lcm_range_primes [0.05790564500057371, 0.05824322199987364, 0.05863306900027965]
lcm_range_fast   [0.06693624800027465, 0.06784769100158883, 0.07562533499913116]

num = 56, loops = 1000
lcm_range_primes [0.057219010001063, 0.05858367799919506, 0.06246676000046136]
lcm_range_fast   [0.06854197999928147, 0.06999059400004626, 0.07505119899906276]

num = 57, loops = 1000
lcm_range_primes [0.05746709300001385, 0.0587476679993415, 0.0606189070003893]
lcm_range_fast   [0.07094627400147147, 0.07241532700027165, 0.07868066799892404]

num = 58, loops = 1000
lcm_range_primes [0.0576490580006066, 0.058481812999161775, 0.05857339500107628]
lcm_range_fast   [0.07127979200049595, 0.07549924399972952, 0.07849203499972646]

num = 59, loops = 1000
lcm_range_primes [0.057503377998727956, 0.058632499998566345, 0.060360438999850885]
lcm_range_fast   [0.07332589399993594, 0.07625177999943844, 0.08087236799838138]

Эта информация о времени была сгенерирована с использованием Python 3.6, работающего на Debian-производном Linux, на старом 2-ГГц процессоре Pentium IV.

Ответ 2

Там есть компромисс между коротким и эффективным.

Короткий путь if all(n % i == 0 for i in range(2, 21)):

Эффективный способ - заметить, что такие вещи, как n % 20 == 0, также означают, что n % f == 0, где f - любой коэффициент 20. Например, вы можете отказаться от n % 2 == 0. Таким образом, вы получите меньше сравнений, которые будут работать быстрее. При этом вы заметите шаблон, и вы заметите, что весь оператор сводится к if n % 232792560 == 0! Но теперь он глубоко встроен в 20, поэтому будет трудно раскрыть, если вам нужен другой верхний предел.

Итак, вы видите, что эффективный способ не так легко читать и поддерживать. Поэтому выберите наиболее подходящий для ваших потребностей.

Ответ 3

if all(n % i == 0 for i in range(2, 21)):

all принимает итерацию и возвращает True, если все ее элементы оцениваются в True, False в противном случае. Часть n % i == 0 for i in range(2, 21) возвращает итерабельность с значениями 19 True или False, в зависимости, если n делится на соответствующее значение i.

Ответ 4

Встроенный все поможет.

Возвращает значение True, если все элементы итерабельного являются истинными (или если итерабельность пуста).

if all(n % i == 0 for i in xrange(2, 21))

Ответ 5

Это просто математический трюк, используйте что-то вроде n % "LCM(1,2,...,20) == 0, которое может быть закодировано как:

if n % 232792560 == 0:
    #do whatever you want

Ответ 6

Для разнообразия, как вы могли бы использовать цикл для этого,

test = True
for modulus in range(2, 21):
    if n % modulus != 0:
        test = False
        break
if test:
    # Do stuff

Если вам комфортно с for - else, вы можете улучшить краткость

for modulus in range(2, 21):
    if n % modulus != 0:
        break
else:
    # Do stuff

хотя этот шаблон может быть достаточно необычным, чтобы вы не хотели его использовать.

Другой вариант - написать вспомогательную функцию

def is_divisible_by_integers_up_to(n, bound):
    for modulus in range(2, bound + 1):
        if n % modulus != 0:
            return False
    return True

if is_divisible_by_integers_up_to(n, 20):
    # Do stuff

Однако этот конкретный пример достаточно прост, что выполнение all с выражением генератора, как описано в других ответах, - лучший способ пойти.

Ответ 7

Вам нужно условие, которое оценивает значение True, когда все деления дают нулевой остаток. Предлагаемые два решения, похоже, не делают этого. Я подозреваю, что вам нужно условие

if not any(n % i for i in range(2, 21)):

Ответ 8

Многие из приведенных выше примеров кода короче, но (возможно) недостаточно эффективны:

n%2 == 0 =>
    n%4 6 8... ==0
n%3 == 0 =>
    n%3 6 9... ==0

Мы можем использовать только простые числа для проверки внутри диапазона:

if all(n % i == 0 for i in [2,3,5,7,11,13,17,19])

Кроме того, если n делит все от 2 до 20, оно делит LCM на 2 на 20.

Ответ 9

Я сам очень легкий пользователь python, и я не знал обо всех. Эти решения довольно круты (и, вероятно, более эффективны, чем тот, который я собираюсь опубликовать). Но если вы хотите увидеть другой способ сделать это, вот еще один вариант:

def IsDivUpTo20(n):
   for i in range(2, 21):
      if n % i != 0:
         return False
   return True

И назовите его так

if IsDivUpTo20(50):
   #what to do if it is divisible
else:
   #what to do if it isn't
#for the example of 50, it'll be false and jump to the else part, but you can put any number of variable in there

Функционально он работает практически так же, как и все, но если вы не привыкли к синтаксису и встроенным фэнтези, это немного интуитивно понятен.

* Примечание. Я использую Python 3, а не Python 2.7, когда вопрос помечен. Я уверен, что это работает в этой версии, но если нет, кто-то, пожалуйста, поправьте меня.

Ответ 10

Как и в предыдущих ответах:

import operator
x = 232792560
if reduce(operator.__and__, [x % n == 0 for n in xrange(2, 21, 2)]):
    print("ok")

Ответ 11

Я не знаю, хорошо ли отвечать на ваш вопрос или нет.

Так как мне нужно проверить. если число делится цифрами от 1 до 20 или нет. Так что это займет много времени, чтобы проверить. Но если бы я мог сделать контрольный список короче, тогда он будет эффективным.

Например, если число делится на 18, то оно также должно делиться на 2 3 6 и 9. Поэтому на основании этого я сделал свой контрольный список:

if all(n % i == 0 for i in [7,11,13,16,17,18,19,20]):

    # some code

И для 14 15 и 12 думаю так.

14: Если число делится как на 2, так и на 7, оно должно делиться на 14.

15: Итак, в случае 15, если число делится на 20, поэтому оно также должно делиться на 5 и если число делится на 18, поэтому оно также должно быть делится на 3, и если число делится на 3 и 5, то оно должно делиться на 15.

Это более эффективно, чем проверка всего числа, а также гарантирует, что число делится на все числа от 1 до 20.