【问题标题】:How to optimally turn a multidimentional list into a single list of items in Python? [duplicate]如何将多维列表最佳地转换为 Python 中的单个项目列表? [复制]
【发布时间】:2011-10-04 11:41:11
【问题描述】:

可能的重复:
Making a flat list out of list of lists in Python
Flatten (an irregular) list of lists in Python

输入一个列表如:[1,2,[3,4,[5,6,7,[8]]],[9],10]

期望的输出:[1,2,3,4,5,6,7,8,9,10]

目前我有以下递归函数:

def fix_list( li , l = [] ):
    for i in li:
        try:
            len( i )
            fix_list( i, l )
        except:
            l.append( i )
    return l

我觉得 try/except 捕获有点花哨和缓慢,我想知道是否有更好/更优化的方法来执行此任务。非常感谢所有输入。

【问题讨论】:

  • 你也可以试试 if type(i) == type(1).
  • 一旦你弄清楚你的函数使用 timeit 模块有多慢(或不慢),就很容易了。
  • 我喜欢这个问题,因为答案说明了对生成器的良好使用,而不是返回一个全新的列表。

标签: python list optimization recursion


【解决方案1】:

这是一个迭代版本(最初是受 Artsiom Rudzenka 的启发),它使用切片分配来修改列表,而不是在每次通过时创建一个新列表。有趣的是,只需要一次通过列表!我对enumerate() 的使用有点不正统;我使用它来跟踪列表中的索引,该索引在我迭代它时可能会增长,但实际上并不使用实际的列表项。

def flattened(items, seqtypes=(list, tuple)):

    items = items[:]  # we will return a copy; remove to mutate original
    for i, _ in enumerate(items):
        while isinstance(items[i], seqtypes):
            items[i:i+1] = items[i]
    return items

print flattened([1,2,[3,4,[5,6,7,[8]]],[9],10])

生成器版本:

def flattener(items, seqtypes=(list, tuple)):

    items = items[:]
    for i, _ in enumerate(items):
        while isinstance(items[i], seqtypes):
            items[i:i+1] = items[i]
        yield items[i]

print list(flattener([1,2,[3,4,[5,6,7,[8]]],[9],10]))

这是一个list 子类,它有一个flatten() 方法。与sort()reverse() 方法一样,这会改变列表并返回None

class listy(list):

    def flatten(self, seqtypes=(list, tuple)):
        for i, _ in enumerate(self):
            while isinstance(self[i], seqtypes):
                self[i:i+1] = self[i]

lst = listy([1,2,[3,4,[5,6,7,[8]]],[9],10])
lst.flatten()
print lst

编辑:我从原始版本中大大简化了这一点。但是,我看到问题已关闭。

【讨论】:

    【解决方案2】:

    另一种方法..

    def flatten(old, new):                                                                                                                      
        for i in old:                                                                                                                           
            flatten(i, new) if isinstance(i, list) else new.append(i)                                                                           
        return new                                                                                                                              
    
    if __name__ == '__main__':                                                                                                                  
        l1 = [1, 2, [3, 4, [5, 6, 7, [8]]], [9], 10]                                                                                            
        l2 = list()                                                                                                                             
        l3 = flatten(l1, l2)                                                                                                                     
        print l3
    

    已简化,因此您不必向展平参数列表提供和清空列表..

    def rec_flatten(old, new=list()):                                                                                                           
        for i in old:                                                                                                                           
            rec_flatten(i, new) if isinstance(i, list) else new.append(i)                                                                       
        return new                                                                                                                              
    
    if __name__ == '__main__':                                                                                                                  
        l1 = [1, 2, [3, 4, [5, 6, 7, [8]]], [9], 10]                                                                                            
        x = rec_flatten(l1)                                                                                                                     
        print x
    

    【讨论】:

    • 你的第二个版本会累积多个列表;尝试在一个脚本中调用它几次。
    【解决方案3】:

    我已经尝试了以下解决方案并且它有效:

    data = [1,2,[3,4,[5,6,7,[8]]],[9],10]
    
    while any(isinstance(x, list) for x in data):
        tmpLst = []
        for x in data:
            if isinstance(x, list):
                tmpLst.extend(x)
            else:
                tmpLst.append(x)
        data = tmpLst
    

    【讨论】:

    • 为什么要在循环结束时复制tmpLst
    • @kindall - 我正在修改初始列表以便能够离开 while 循环。
    • 是的,但在我看来 data = tmpLst 可以正常工作,无需使用切片/副本,因为 tmpLst 已经是原始列表的副本。
    • 已经尝试过了,是的 - 似乎你是对的(我只是将它与 [:] 一起使用,以免在浅/深复制时出现错误)。
    【解决方案4】:

    这是一个简单的生成器:

    def flatten(nested):
        for item in nested:
            if isinstance(item, collections.Iterable) and not isinstance(item, basestring):
                for inner_item in flatten(item):
                    yield inner_item
            else:
                yield item
    

    不确定它是否“最佳”。

    【讨论】:

    • 您是否只是复制了该解决方案并将变量重命名为您自己的?
    • @phant0m,不,我从前段时间写的一个脚本中复制了它,试图理解递归生成器。不过,我对它与发布的一个夜莺的相似之处感到不安。
    • 我的看起来完全一样,除了在检查可迭代时我使用 hasattr(el, '__iter__')。其余的几乎相同。任何人在这上面花费 15 分钟都会得出或多或少相同的解决方案。
    【解决方案5】:

    this answer:

    def flatten(l):
        for el in l:
            if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
                for sub in flatten(el):
                    yield sub
            else:
                yield el
    

    【讨论】:

    • @Gandi:好吧,至少我说我从哪里得到的,senderle 没有。
    • 我没说有什么问题。
    • 这并不意味着您应该将其发布为 aswer 恕我直言;但请注意,它与另一个问题重复。
    • @nightcracker,我在试图了解如何创建递归生成器的过程中写了它:)。不过,非常相似,不是吗?
    猜你喜欢
    • 1970-01-01
    • 2019-09-24
    • 2017-12-06
    • 2015-06-18
    • 2016-01-18
    • 2022-01-17
    • 2017-03-25
    • 2021-05-26
    • 1970-01-01
    相关资源
    最近更新 更多