【问题标题】:How do I flatten nested lists of lists in python?如何在 python 中展平嵌套的列表列表?
【发布时间】:2015-04-13 02:47:58
【问题描述】:

我创建了一个函数来将路径拆分为 python 中的目录列表,如下所示:

splitAllPaths = lambda path: flatten([[splitAllPaths(start), end] if start else end for (start, end) in [os.path.split(path)]])

使用这个辅助函数:

#these only work one directory deep
def flatten(list_of_lists):
    return list(itertools.chain.from_iterable(list_of_lists))

此函数的输出如下所示:

> splitAllPaths('./dirname/dirname2/foo.bar')
[[[['.'], 'dirname'], 'dirname2'], 'foo.bar']

现在我希望这是一个平面列表。我的尝试如下(带有输出):

> flatten(splitAllPaths('./diname/dirname2/foo.bar'))
['.', 'd', 'i', 'r', 'n', 'a', 'm', 'e', 'd', 'i', 'r', 'n', 'a', 'm', 'e', '2', 'f', 'o', 'o', '.', 'b', 'a', 'r']

> reduce(list.__add__, (list(mi) for mi in splitAllPaths('./dirname/dirname2/foo.bar')))
me2/foo.bar')))
[[['.'], 'dirname'], 'dirname2', 'f', 'o', 'o', '.', 'b', 'a', 'r']

如何正确展开此列表(我也欢迎任何关于如何改进我的splitAllPaths 功能的建议)?

【问题讨论】:

  • 期望的输出是['.', 'dirname', 'dirname2', 'foo.bar']?
  • 你必须检查元素是strs
  • @TimCastelijns,是的。
  • 但是你为什么不直接做"./dirname/dirname2/foo.bar".split("/")呢?
  • 随便看看this

标签: python list reduce fold


【解决方案1】:

这是一个不太笼统的答案,但它解决了你原来的问题——尽管它的优雅值得商榷。

主要思想是使用 reversed 生成列表(如['file', 'user', 'home', '/'] 顺序非常容易,因此您可以创建它并在最后反转它。所以它沸腾了到:

def split_paths(path):                                                       
    def split_paths_reverse(path):                                           
        head, tail = os.path.split(path)                                     
        while head and tail:                                                 
            yield tail                                                                                
            head, tail = os.path.split(head)                                 
        yield head                                                           

    return reversed(tuple(split_paths_reverse(path)))

例子:

test = '/home/user/file.txt'
print(list(split_paths(test)))

['/', 'home', 'user', 'file.txt']

您也可以通过将每个元素放入堆栈然后删除它们来避免显式反转部分,但这取决于您。

【讨论】:

    【解决方案2】:

    想到的排序方法是:

    listoflists = [[[['.'], 'dirname'], 'dirname2'], 'foo.bar']
    str(listoflists).translate(None,"[]'").split(',')
    

    【讨论】:

    • 这个例子应该是, (注意逗号空格),虽然它很简单(你的意思是说最简单而不是排序?)我不喜欢转换数据 -将结构转换为字符串(也可能是eval-ing 它们),这也会与包含任何字符[]', 的路径名中断
    • 我会更关心包含','的目录名称,但那。如果它对你不起作用,那没关系,我只是想展示一种简单的方法来做到这一点(对其他人来说可能有用)。
    • 不,它很好,教会了我我不知道的翻译方法。谢谢
    【解决方案3】:

    我通过编写一个(非通用)foldr 解决了这个问题。我认为在 cmets 中 @L3viathan 提供了更好、更实用的解决方案。

    attempt = lambda list: attempt(list[0] + list[1:]) if len(list[0]) > 1 else list[0] + list[1:]
    

    输出

    > attempt([[[['.'], 'dirname'], 'dirname2'], 'foo.bar'])
    ['.', 'dirname', 'dirname2', 'foo.bar']
    

    我现在也写成一般的foldr1

    > foldr1 = lambda func, list: foldr1(func, func(list[0], list[1:])) if len(list[0]) > 1 else func(list[0], list[1:])
    > foldr1(list.__add__, [[[['.'], 'dirname'], 'dirname2'], 'foo.bar'])
    ['.', 'dirname', 'dirname2', 'foo.bar']
    

    注意:比我更熟悉的人能否确认这是一个 foldr 而不是 foldl(我经常让他们感到困惑)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-04
      • 2018-05-06
      • 2012-03-09
      • 2018-06-24
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多