I have a class whose __iter__()
method return a itertools.product()
of a dynamically generated data.
This data do a Cartesian product of arbitrarily nested dicts, and now I need to flatten it, but in a streamlined way, aggregating intermediate iterators.
I'm trying either of these:
Modify __iter__()
to handle the internal tuples:
class Explosion:
...
def __iter__(self):
return product(*self.fragments)
Encapsulate it in another object to handle the conversion, but this is less desirable:
class CleanOutput:
def __init__(self, it):
self.it = it
def next(self):
for x in self.it:
yield ?
class Explosion:
...
def __iter__(self):
return CleanOutput(product(*self.fragments))
Well, the algorithm does work, but the problem is the unpacking at the final, for example:
(11, ..., (10.7, 104.75, ('N', True, False, 'B2B'), 99.01, ...), 1, 'SP', 7)
.
Look at all the nesting! How to remove it in real-time
? While it is being generated...
I'm looking for a way retrieve:
(11, ..., 10.7, 104.75, 'N', True, False, 'B2B', 99.01, ..., 1, 'SP', 7)
.
What is the best and fastest way to do it? Thank you!
EDIT
Actually, what I'd really like was a list comprehension or a generator expression or even another generator, because I needed to include it in a callable, intercepting the output of the itertools.product()
itself. I don't simply need a way to clean these tuples. So it isn't a duplicate.
That wasn't easy, the recursion has to be used, but separated from the main __iter__
method. That's how I ended up doing.
Now also with a recursive generator _merge
, called by another generator _flatten
:
class Explosion:
# ...
def __iter__(self):
def _flatten(container):
def _merge(t):
for te in t:
if isinstance(te, tuple):
for ite in _merge(te):
yield ite
else:
yield te
for t in container:
yield tuple(_merge(t))
return _flatten(product(*self.fragments))
See an example of utilization of the _flatten()
function:
>>> list(itertools.product([1,2],[3,(4,(5,6))]))
[(1, 3), (1, (4, (5, 6))), (2, 3), (2, (4, (5, 6)))]
>>> list(_flatten(itertools.product([1,2],[3,(4,(5,6))])))
[(1, 3), (1, 4, 5, 6), (2, 3), (2, 4, 5, 6)]