之前已经提出了类似的问题,但这些问题的解决方案对我的用例不起作用(例如,Making a flat list out of list of lists in Python和Flattening a shallow list in Python。我有一个字符串和列表的列表,其中嵌入了list也可以包含字符串和列表。我想把它变成一个简单的字符串列表,而不将字符串拆分成字符列表。
import itertools
list_of_menuitems = ['image10', ['image00', 'image01'], ['image02', ['image03', 'image04']]]
chain = itertools.chain(*list_of_menuitems)
结果清单:
['i', 'm', 'a', 'g', 'e', '1', '0', 'image00', 'image01', 'image02', ['image03', 'image04']]
预期结果:
['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
最好的(Pythonic)方法是什么?
答案 0 :(得分:11)
可以通过简单的修改将经常重复的flatten
函数应用于此情况。
from collections import Iterable
def flatten(coll):
for i in coll:
if isinstance(i, Iterable) and not isinstance(i, basestring):
for subc in flatten(i):
yield subc
else:
yield i
basestring
将确保str
和unicode
对象不会被拆分。
还有一些版本依赖i
没有__iter__
属性。我不知道所有这些,因为我认为str
现在具有该属性。但是,值得一提。
(请关注相关答案。)
答案 1 :(得分:4)
以下适用于字符串(并且很容易适应其他类型):
def flatten_to_strings(listOfLists):
"""Flatten a list of (lists of (lists of strings)) for any level
of nesting"""
result = []
for i in listOfLists:
# Only append if i is a basestring (superclass of string)
if isinstance(i, basestring):
result.append(i)
# Otherwise call this function recursively
else:
result.extend(flatten_to_strings(i))
return result
flatten_to_strings(list_of_menuitems)
Out[2]: ['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
答案 2 :(得分:4)
使用递归。
def flattern(A):
rt = []
for i in A:
if isinstance(i,list): rt.extend(flattern(i))
else: rt.append(i)
return rt
测试:
>>> list_of_menuitems = ['image10', ['image00', 'image01'], ['image02', ['image0
3', 'image04']]]
>>> flattern(list_of_menuitems)
['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
答案 3 :(得分:1)
在一个特殊情况下,如果列表项都不包含以下分隔符之一[]'
,则可以使用以下hack。我没有对它进行分析,但看起来很明显,这将比明显更清晰的递归解决方案具有更好的性能。
>>> str(list_of_menuitems).translate(None,"[]'").split(',')
['image10', ' image00', ' image01', ' image02', ' image03', ' image04']
我同意,这是一个肮脏的黑客攻击,但是JOB没有太多努力。
答案 4 :(得分:1)
这是一个通用的递归展平,可以用于任何应该或不应该展平的类型组合:
import collections
def generic_flatten(seq, flatten_types=(tuple,list,set),atom_types=(basestring,dict),fixtype=True):
newseq = []
for item in seq:
if (not isinstance(collections.Iterable)) or any(isinstance(i,t) for t in atom_types):
newseq.append(item)
elif any(isinstance(i,t) for t in flatten_types): # set flatten_types to (object,) or (collections.Iterable,) to disable check
newseq.extend(generic_flatten(item, flatten_types, atom_types,fixtype)
if fixtype and type(newseq) is not type(seq):
newseq = type(seq)(newseq)
return newseq
yield
和chain
可用于创建基于迭代器的通用版本。