Filter map versus list comprehension

Is a filter / map equivalent to list comprehension? Suppose I have the following function

def fib_gen(): a,b = 0,1 yield 0 yield 1 while True: a,b = b,a+b yield b 

Now I can use list counting to list fib numbers:

 a = fib_gen() print [a.next() for i in range(int(sys.argv[1]))] 

Suppose I want to list only even numbers of fics. I would do the following with a filter / map:

 a = fib_gen() print filter(even, map(lambda x: a.next(), range(int(sys.argv[1])))) 

How to get the same result with a list?

+6
source share
6 answers

You can use the generator to store the intermediate result and "filter" on it.

 fibs = (a.next() for i in whatever) even_fibs = [num for num in fibs if num % 2 == 0] 

or in one line:

 even_fibs = [num for num in (a.next() for i in whatever) if num % 2 == 0] 

Note that if you want to take a certain number of elements from an iterator, instead of itertools.islice :

 from itertools import islice fibs_max_count = int(sys.argv[1]) even_fibs = [num for num in islice(fib_gen(), fibs_max_count) if num%2 == 0] 
+9
source

Is a filter / map equivalent to list comprehension?

Yes, map(f, L) equivalent to [f(x) for x in L] . filter(f, L) equivalent to [x for x in L if f(x)] . But, since lists with side effects are generally bad (and here you change the state of the generator), you can use itertools for a bit:

  a = fib_gen() a = itertools.islice(a, int(sys.argv[1])) a = itertools.ifilter(even, a) print list(a) 
+13
source

filter and map easily converted to list comprehension.

Here is a basic example:

 [hex(n) for n in range(0, 100) if n > 20] 

This is equivalent to:

 list(map(hex, filter(lambda x: x > 20, range(0, 100)))) 

Understanding, in my opinion, is more readable. However, if the conditions become very advanced, I prefer filter .

So in your case:

 [n for n in itertools.islice(fib_gen(), 100) if even(n)] 

I used islice here because the sequence is infinite. But if you use a generator expression, it also becomes an endless stream:

 gen = (n for n in fib_gen() if even(n)) 

Now you can also slice the sequence using islice :

 print itertools.islice(gen, int(sys.argv[1])) 

This avoids the need to use next in the insights themselves. Until you try to evaluate an infinite sequence (as if we skipped islice in list comprehension), we can work with your sequence.

+6
source

I do not think this will work with a generator. To have this work with a list, you will need:

 print [a.next() for i in range(int(sys.argv[1])) if even(a.next())] 

This returns:

 [1, 3, 13, 55, 233] 

The problem is that you need to access the next number in the list, but the second call to a.next () does what it should do, i.e. get the next number. As far as I know, it is impossible to save the value of a.next () with a list in order to use it twice.

+1
source

You can use the following code:

 a = fib_gen() print [a.next() for i in range(int(sys.argv[1])) if i%3==0] 

This is a special case that works because every third fibonacci number is even.

+1
source

You can always generate even Fibo numbers ...

 def evenfib(): """ Generates the even fibonacci numbers """ a, b = 2, 0 while True: a, b = b, a+4*b yield a 
0
source

Source: https://habr.com/ru/post/890861/


All Articles