Очистить динамически генерируемые вложенные кортежи
Я реализовал алгоритм, чтобы сделать декартово произведение произвольно вложенных диктов в Python. Поля, находящиеся на корневом уровне, необходимо реплицировать в несколько строк, поскольку в него могут быть также вложены массивы. Я использовал itertools.product
рекурсивно, агрегируя промежуточные итераторы.
Работает, но проблема в распаковке на финале. Я получил такую структуру:
(11, 12.2, 123.2, 1.23, 104.75, (10.7, 104.75, 104.75, ('N', True, False, 'B2B'), 99.01, 6.3, 1.23, 5.87, 12.2), 1, 'SP', 7)
,
Я ищу понимание списка, выражение генератора или даже полноценный генератор, который может сгладить и очистить этот ряд, чтобы:
(11, 12.2, 123.2, 1.23, 104.75, 10.7, 104.75, 104.75, 'N', True, False, 'B2B', 99.01, 6.3, 1.23, 5.87, 12.2, 1, 'SP', 7)
,
Какой самый лучший и быстрый способ сделать это?
РЕДАКТИРОВАТЬ
На самом деле, я попросил понять список или выражение генератора или даже полноценный генератор, потому что мне нужно включить его в ловушку, перехватывая выходные данные itertools.product
сам. Мне просто не нужен способ почистить эти чаши. Так что это не дубликат.
Ребята, пожалуйста, я не хочу никакой рекурсивной функции для этого! У меня есть класс, чей __iter__()
метод вернуть itertools.product
динамически генерируемых данных. Я пытаюсь любой из этих:
Измените этот метод для обработки внутренних кортежей:
class Explosion: ... def __iter__(self): return product(*self.fragments)
Инкапсулируйте в другой объект, обрабатывающий преобразование, но это менее желательно:
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))
2 ответа
def gen(data):
for item in data:
if isinstance(item, tuple):
for nested in gen(item):
yield nested
else:
yield item
Не проверено, но должно работать.
Это было непросто, рекурсия должна быть использована, но отделена от основной __iter__
метод. Вот так я и сделал. Теперь также с рекурсивным генератором _merge
вызывается другим генератором _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))
Смотрите пример использования _flatten()
функция:
>>> 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)]