Нахождение простых чисел с модулем в Python
Я потел над этим фрагментом кода, который возвращает все простые числа в списке:
primes = range(2, 20) 
for i in range(2, 8): 
     primes = filter(lambda x: x == i or x % i, primes)
print primes
Это работает... но я не понимаю, какую роль "x == i or x % i" играет во всем этом.
Когда я удаляю компонент x % i, я ожидаю, что этот код даст мне числа, общие для обоих множеств, но это не так: 
nums = [2, 20] 
for i in range(2, 8): 
     nums = filter(lambda x: x == i, nums)
print nums
Почему это?
Аналогичным образом, когда я удаляю компонентx == i, он возвращает простые числа от 11 до 19. 
nums = range(2, 20) 
for i in range(2, 8): 
     nums = filter(lambda x: x % i, nums)
print nums
Опять же, я не понимаю, почему он игнорирует все простые числа ниже 11.
Затем я попробовал это:
nums = [13] 
for i in range(2, 8): 
     nums = filter(lambda x: x % i, nums)
print nums
Опять же, это не имеет для меня никакого смысла. Лямбда повторяется над x в nums правильно? И i повторяется в диапазоне от 2 до 7. Итак, разве мы не берем 13 % i... от 2 до 7? Как получается ли это "13"?
Используя ту же логику, что и непосредственно выше, я сделал то же самое с "13", но используя x == i в лямбде. 
for i in range(2, 8): 
     nums = filter(lambda x: x == i, nums)
print nums
И, как я и ожидал, он вернул пустой список - что имеет смысл в моем уме, потому что 13 никогда не появляется в диапазоне от 2 до 7.
Для справки о тех, кто пытается помочь, это образ мышления, в котором я нахожусь, когда работаю с filter() и лямбдами: 
a = range (1, 11)
b = range (9, 20) 
for i in filter(lambda x: x in a, b):
    print i,
Это, конечно, дает нам "9 10". Я знаю структуру петли это другое, но, надеюсь, это поможет вам увидеть, где лежит моя путаница.
Я работал с filter() и лямбдами довольно широко, поэтому я думал, что смогу понять это, но я в тупике! Я просто надеюсь, что ответ не настолько очевиден, чтобы я чувствовал себя идиотом...
4 ответа:
Это выглядит как компактная (но несколько неясная) реализация сита Эратосфена [EDIT: как указано в комментариях, это на самом деле" неверное сито", поскольку пробное разделение вызывает худшую временную сложность, чем фактическое сито Эратосфена].
Первая строка-это просто произвольный диапазон поиска последовательных целых чисел для фильтрации простых чисел:primes = range(2, 20)Далее, следуя алгоритму сита , мы повторяем с целым числом i в диапазоне (2, n) где n-наивно самое большое число в диапазоне поиска (хотя в этом случае 7-выбранная верхняя граница-подробнее об этом ниже).
Алгоритм утверждает, что мы включаем i и исключаем кратные i. Вот для чего нужен фильтр лямбда-предикатов --for i in range(2, 8): primes = filter(lambda x: x == i or x % i, primes)Верхняя граница 8 кажется несколько произвольной - как минимум, нам нужно искать только до
- включить i:
 x == 1- исключите кратные i:
 x % i- это короткая рука дляx % i != 0. Другими словами, x не делится на i, или, наоборот, x не кратно i.sqrt(n), так какsqrt(n) * sqrt(n) = nозначает, чтоsqrt(n)является верхней границей пространства поиска. Квадратный корень из 19 равен приблизительно 4,4, и в этом примере вы видите, что список простых чисел не изменяется после i = 3.In [18]: primes = range(2, 20) In [19]: for i in range(2, 8): ....: primes = filter(lambda x: x == i or x % i, primes) ....: print i, primes ....: 2 [2, 3, 5, 7, 9, 11, 13, 15, 17, 19] 3 [2, 3, 5, 7, 11, 13, 17, 19] 4 [2, 3, 5, 7, 11, 13, 17, 19] 5 [2, 3, 5, 7, 11, 13, 17, 19] 6 [2, 3, 5, 7, 11, 13, 17, 19] 7 [2, 3, 5, 7, 11, 13, 17, 19]
Первый блок кода, который вы опубликовали, является самым простым примером для меня, чтобы объяснить это:
primes = range(2, 20) for i in range(2, 8): primes = filter(lambda x: x == i or x % i, primes) print primesПри использовании метода сита Эратосфена важно отметить, что вам нужно только удалить числа, которые являются произведениями чисел до квадратного корня из max. Использование
range(2,8)выше реализует это (оно идет от 2 до 7, что дальше, чем необходимо). Квадратный корень из 19 (наибольшее число во внешнем диапазоне, которое проверяется) находится между 4 и 5. Таким образом, наибольшее число, которое должно быть проверено в диапазоне, равно 4 (нам нужно только проверить целые числа).Используя эти знания, вы можете улучшить код следующим образом (это находит простые числа
Обратите внимание, что вместо использованияimport math max = 19 #Set it here max += 1 primes = range(2, max) for i in range(2, int( math.ceil(math.sqrt(max)) )): primes = filter(lambda x: x == i or x % i, primes) print primesfloorи последующего добавления одного, посколькуrangeявляется исключительным, я используюceil.Запустите его здесь: http://repl.it/8N8
Edit: я также понял, что это (и код, приведенный в вопросе) не является полной реализацией метода sieve, поскольку в соответствии с алгоритмом мы должны только помечать кратные простые числа , это означает, что внутреннее использование
rangeне так эффективно, как должно быть.Увидеть графическое изображение алгоритма в прогресс:
Я написал простой список понимания для генерации простых чисел. Конечно, основная идея была скопирована в переполнении стека. Честно говоря, мне потребовалось время, чтобы понять это, поскольку я был новичком в python. Я использовал этот список понимание путем вызов лямбда-функции отдельно. Поэтому сначала я рассмотрю лямбда-функцию.
лямбда-функция: is_prime = lambda x: all(x % y != 0 для y в диапазоне (2, int (math.sqrt (x)) + 1))
Теперь понимание списка с помощью выше лямбды.
Простые числа = [x для x в диапазоне (30), если is_prime (x) = = True]
Я думаю, что ответ довольно прост. Увеличьте набор простых чисел с диапазона (2,20) до диапазона(2,30) и повторите мысленный эксперимент. Это будет мне гораздо более очевидно.
Функция фильтра будет возвращать значения для диапазона диапазона (2,20), что
filter(lambda x: x == i or x % i, primes)Возвращает true.
В дополнение к увеличению простых чисел от диапазона (2,20) до диапазона (2,30), поиграйте с вашими внутренними критериями фильтра, и вы начнете видеть различия, которые вы ищете для.
#!/usr/bin/python primes = range(2, 30) for i in range(2, 3): primes = filter(lambda x: x == i or x % i, primes) print primesВ результате чего:
[2, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]И
#!/usr/bin/python primes = range(2, 30) for i in range(2, 4): primes = filter(lambda x: x == i or x % i, primes) print primesПриводит к
[2, 3, 5, 7, 11, 13, 17, 19, 23, 25, 29]
