Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does python have a built-in function for interleaving generators/sequences?

I noticed that itertools does not (it seems to me) have a function capable of interleaving elements from several other iterable objects (as opposed to zipping them):

def leaf(*args): return (it.next() for it in cycle(imap(chain,args)))
tuple(leaf(['Johann', 'Sebastian', 'Bach'], repeat(' '))) => ('Johann', ' ', 'Sebastian', ' ', 'Bach', ' ')

(Edit) The reason I ask is because I want to avoid unnecessary zip/flatten occurrences.

Obviously, the definition of leaf is simple enough, but if there is a predefined function that does the same thing, I would prefer to use that, or a very clear generator expression. Is there such a function built-in, in itertools, or in some other well-known library, or a suitable idiomatic expression?

Edit 2: An even more concise definition is possible (using the functional package):

from itertools import *
from functional import *

compose_mult = partial(reduce, compose)
leaf = compose_mult((partial(imap, next), cycle, partial(imap, chain), lambda *args: args))
like image 857
Marcin Avatar asked Jan 07 '12 12:01

Marcin


People also ask

What is a generator function in Python?

Python generators are a simple way of creating iterators. All the work we mentioned above are automatically handled by generators in Python. Simply speaking, a generator is a function that returns an object (iterator) which we can iterate over (one value at a time).

How do you create a generator in Python?

Generator-Function : A generator-function is defined like a normal function, but whenever it needs to generate a value, it does so with the yield keyword rather than return. If the body of a def contains yield, the function automatically becomes a generator function.

How do you access the generator object in Python?

You need to call next() or loop through the generator object to access the values produced by the generator expression. When there isn't the next value in the generator object, a StopIteration exception is thrown. A for loop can be used to iterate the generator object.


1 Answers

You're looking for the built-in zip and itertools.chain.from_iterable to flatten the result:

>>> import itertools
>>> list(zip(['Johann', 'Sebastian', 'Bach'], itertools.repeat(' ')))
[('Johann', ' '), ('Sebastian', ' '), ('Bach', ' ')]
>>> list(itertools.chain.from_iterable(_))
['Johann', ' ', 'Sebastian', ' ', 'Bach', ' ']

Note that I used list just to force a nice output. Using the standard itertools, alternative implementations for leaf would be:

leaf = lambda *a: itertools.chain.from_iterable(itertools.izip(*a)) # Python 2.x
leaf = lambda *a: itertools.chain.from_iterable(zip(*a))            # Python 3.x
like image 84
phihag Avatar answered Oct 11 '22 09:10

phihag