# Odd behavior of stacked filter() calls

 Refresh November 2018 Views 123 time
5

So I'm getting some interesting behaviour from some filters stacked within a for loop. I'll start with a demonstration:

``````>>> x = range(100)
>>> x = filter(lambda n: n % 2 == 0, x)
>>> x = filter(lambda n: n % 3 == 0, x)
>>> list(x)
[0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]
``````

Here we get the expected output. We have a range within a filter within a filter, and the filter conditions are stacking as we want them to. Now here comes my problem.
I have written a function for calculating the relative primes of a number. It looks like this:

``````def relative_primes(num):
'''Returns a list of relative primes, relative to the given number.'''
if num == 1:
return []
elif is_prime(num):
return list(range(1, num))
result = range(1, num)
for factor in prime_factors(num):
# Why aren't these filters stacking properly?
result = filter(lambda n: n % factor != 0, result)
return list(result)
``````

For whatever reason, the filter is only being applied to the LAST factor in the list acquired from prime_factors(). Example:

``````>>> prime_factors(30)
[2, 3, 5]
>>> relative_primes(30)
[1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29]
``````

We can see that no multiples of 2 or 3 were removed from the list. Why is this happening? Why does the above example work, but the filters in the for loop don't?

7

В Python 3.x, `filter()`возвращает генератор вместо списка. По существу, только конечное значение `factor`привыкает , так как все три фильтра использовать то же самое `factor`. Вам нужно будет немного изменить свою лямбду, чтобы заставить его работать.

``````result = filter(lambda n, factor=factor: n % factor != 0, result)
``````
1

Оценка итераторы лень. Все фильтры будут оценены только в отчете

``````return list(result)
``````

К тому времени, значение `factor`является последним главным фактором. В `lambda`функции содержит только ссылку на локальное имя `factor`и будет использовать любое значение присваивается этим имя во время исполнения.

Один из способов исправить это преобразовать в список в каждой итерации.

Как Замечание, гораздо проще реализация этой функции

``````from fractions import gcd
def relative_primes(n):
return [i for i in range(1, n) if gcd(n, i) == 1]
``````

Edit : Если вы после выполнения вместо простоты, вы можете попробовать это:

``````def relative_primes(n):
sieve =  * n
for i in range(2, n):
if not sieve[i] or n % i:
continue
sieve[::i] =  * (n // i)
return list(itertools.compress(range(n), sieve))
``````
1

Если я вас понял правильно и два целых числа взаимно просты , если они не разделяют никаких общих позитивные факторов (дивизоры) за исключением 1. Используя обозначения для обозначения наибольшего общего делителя два целых чисел а и Ь взаимно просты , если НОД (а, Ь) = = 1. то вы можете использовать дроби модуль следующим образом.

``````from fractions import gcd

num = 30
relative_primes = filter(lambda x: gcd(x,num) == 1, xrange(1,num))
``````