Accounting for alternative values ββin iterations
I am given several iterations, I need to produce all values ββin the first iterable and then everything in the second, ..., all values ββin the last iterable.
Example :
for i in alternate('abcde','fg','hijk'):
print(i,end=' ')
Values ββare expected to be received
a f h b g i c
I know to print all characters in a sequence like
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'
Here is the code:
def alternate(*args):
for iterable in args:
for item in iterable:
yield item
But how can I give them as an alternative?
source to share
If you want to end up in the shortest list then use zip
:
Create an iterator that combines elements from each of the repeating ones.
def alternate(*args):
# note: python 2 - use izip_longest
for iterable in zip(*args):
for item in iterable:
if item is not None:
yield item
If you want to use all elements, use itertools.izip_longest :
Make an iterator that combines elements from each of the repeating ones. If the iterators are of uneven length, the missing values ββare filled with fillvalue.
def alternate(*args):
# note: python 2 - use izip_longest
for iterable in itertools.zip_longest(*args):
for item in iterable:
if item is not None:
yield item
Note that it is missing values None
(can be changed with fillvalue
).
Without itertools
:
def alternate(*args):
max_len = max(map(len, args))
for index in range(max_len):
for lst in args:
try:
yield lst[index]
except IndexError:
continue
To stop the first "missing" element:
def alternate(*args):
index = 0
while True:
for lst in args:
try:
yield lst[index]
except IndexError:
return
index += 1
And if you use generators (or iterators) you get StopIteration
when one of them is executed, so you can use iter
to create a generic function:
def alternate(*args):
iters = [iter(lst) for lst in args]
while True:
for itr in iters:
try:
yield next(itr)
except StopIteration:
return
source to share
This will do what you want. It works for any input, it won't fire if one of the elements None
. It uses built-in module itertools
and will work on python 3.x and python 2.7 with python built-in modules only. It is based on roundrobin
from the Python documentation itertools
:
from itertools import cycle
def roundrobin_shortest(*iterables):
"roundrobin_shortest('ABCD', 'EF', 'GHI') --> A E G B F H C"
nexts = cycle(iter(it).__next__ for it in iterables)
while True:
try:
for inext in nexts:
yield inext()
except StopIteration:
break
This version works basically the same, but is a little shorter:
from itertools import chain, cycle
def roundrobin_shortest(*iterables):
"roundrobin_shortest('ABCD', 'EF', 'GHI') --> A E G B F H C"
nexts = cycle(iter(it).__next__ for it in iterables)
yield from chain.from_iterable(inext() for inext in nexts)
And the version without itertools:
def roundrobin_shortest(*iterables):
"roundrobin_shortest('ABCD', 'EF', 'GHI') --> A E G B F H C"
items = [iter(item) for item in iterables]
while True:
try:
for it in items:
yield next(it)
except StopIteration:
break
You can use any of them, for example:
>>> for i in roundrobin_shortest('abcde','fg','hijk'):
... print(i, end=' ')
...
a f h b g i c
Or here's a simpler one-liner
>>> from itertools import chain, cycle
>>> iters = ('abcde','fg','hijk')
>>> res = chain.from_iterable(j() for j in cycle(iter(j).__next__ for j in iters))
>>> print(' '.join(res))
a f h b g i c
source to share