2015-06-16 5 views
2

Если у меня есть список списка списка кортежей из двух строк. Я хочу, чтобы сгладить его в невложенный список кортежей, я мог бы сделать это:Есть ли способ избежать так много списка (chain (* list_of_list))?

>>> from itertools import chain 
>>> lst_of_lst_of_lst_of_tuples = [ [[('ab', 'cd'), ('ef', 'gh')], [('ij', 'kl'), ('mn', 'op')]], [[('qr', 'st'), ('uv', 'w')], [('x', 'y'), ('z', 'foobar')]] ] 
>>> lllt = lst_of_lst_of_lst_of_tuples 
>>> list(chain(*list(chain(*lllt)))) 
[('ab', 'cd'), ('ef', 'gh'), ('ij', 'kl'), ('mn', 'op'), ('qr', 'st'), ('uv', 'w'), ('x', 'y'), ('z', 'foobar')] 

Но есть еще один способ распаковки в невложенный список кортежей withou вложенной list(chain(*lst_of_lst))?

ответ

2

вы можете держать распаковка, пока не упретесь кортежи:

def unpack_until(data, type_): 
    for entry in data: 
     if isinstance(entry, type_): 
      yield entry 
     else: 
      yield from unpack_until(entry, type_) 

Затем:

>>> list(unpack_until(lllt, tuple)) 
[('ab', 'cd'), 
('ef', 'gh'), 
('ij', 'kl'), 
('mn', 'op'), 
('qr', 'st'), 
('uv', 'w'), 
('x', 'y'), 
('z', 'foobar')] 
4

Вам не нужно звонить list перед распаковкой итератор:

list(chain(*chain(*lllt))) 

Это может быть лучше использовать chain.from_iterable вместо распаковки, чтобы работать с итератора вместо материализовать их в кортежах с *:

flatten = chain.from_iterable 
list(flatten(flatten(lllt)))