代码之家  ›  专栏  ›  技术社区  ›  Steve Cooper

python列表理解;压缩列表?

  •  57
  • Steve Cooper  · 技术社区  · 15 年前

    伙计们。我试图找到一个问题的最优雅的解决方案,并想知道Python是否有任何内置的功能来实现我所要做的。

    我要做的就是这个。我有一张单子, A 我有一个功能 f 它接受一个项目并返回一个列表。我可以用列表理解来转换 像这样;

    [f(a) for a in A]
    

    但这会返回一个列表;

    [a1,a2,a3] => [[b11,b12],[b21,b22],[b31,b32]]
    

    我真正想要的是得到一份扁平的清单;

    [b11,b12,b21,b22,b31,b32]
    

    现在,其他语言也有了,传统上叫做 flatmap 在函数式编程语言中,.NET调用它 SelectMany . 巨蟒有类似的东西吗?有没有一种简单的方法可以将一个函数映射到一个列表上并将结果变平?

    我要解决的实际问题是:从目录列表开始,查找所有子目录。所以;

    import os
    dirs = ["c:\\usr", "c:\\temp"]
    subs = [os.listdir(d) for d in dirs]
    print subs
    

    currentlie给了我一个列表,但我真的想要一个列表。

    13 回复  |  直到 7 年前
        1
  •  85
  •   Ants Aasma    15 年前

    您可以在单个列表理解中进行嵌套迭代:

    [filename for path in dirs for filename in os.listdir(path)]
    
        2
  •  60
  •   Julian    15 年前
    >>> listOfLists = [[1, 2],[3, 4, 5], [6]]
    >>> reduce(list.__add__, listOfLists)
    [1, 2, 3, 4, 5, 6]
    

    我猜Itertools解决方案比这更有效,但这让人感觉非常恶心,并且避免了仅仅为了一个列表操作而导入一个库。

        3
  •  44
  •   rob    15 年前

    你可以在 itertools' recipes:

    def flatten(listOfLists):
        return list(chain.from_iterable(listOfLists))
    

    (注意:需要python 2.6+)

        4
  •  20
  •   Wai Yip Tung    11 年前

    提出的问题 flatmap .提出了一些实现,但它们可能不需要创建中间列表。这里是一个基于迭代器的实现。

    def flatmap(func, *iterable):
        return itertools.chain.from_iterable(map(func, *iterable))
    
    In [148]: list(flatmap(os.listdir, ['c:/mfg','c:/Intel']))
    Out[148]: ['SPEC.pdf', 'W7ADD64EN006.cdr', 'W7ADD64EN006.pdf', 'ExtremeGraphics', 'Logs']
    

    在python 2.x中,使用 itertools.map 代替 map .

        5
  •  15
  •   Anon    15 年前

    你可以直接做:

    subs = []
    for d in dirs:
        subs.extend(os.listdir(d))
    
        6
  •  10
  •   Community CDub    7 年前

    可以使用普通加法运算符连接列表:

    >>> [1, 2] + [3, 4]
    [1, 2, 3, 4]
    

    内置功能 sum 将按顺序添加数字,并可以选择从特定值开始:

    >>> sum(xrange(10), 100)
    145
    

    将上面的内容合并以展开列表:

    >>> sum([[1, 2], [3, 4]], [])
    [1, 2, 3, 4]
    

    现在您可以定义 flatmap :

    >>> def flatmap(f, seq):
    ...   return sum([f(s) for s in seq], [])
    ... 
    >>> flatmap(range, [1,2,3])
    [0, 0, 1, 0, 1, 2]
    

    编辑: 我刚刚在评论中看到了 another answer 我想这是正确的,python将不必要地构建和垃圾收集许多较小的列表与此解决方案。因此,最好的一点是,如果你习惯于函数式编程,它会非常简单和简洁。

        7
  •  10
  •   Darknight    12 年前
    import itertools
    x=[['b11','b12'],['b21','b22'],['b31']]
    y=list(itertools.chain(*x))
    print y
    

    Itertools将从python2.3及更高版本开始工作。

        8
  •  7
  •   RichieHindle    15 年前
    subs = []
    map(subs.extend, (os.listdir(d) for d in dirs))
    

    (但蚂蚁的回答更好,他要加1)

        9
  •  3
  •   Steef    15 年前

    你可以试试 itertools.chain() ,像这样:

    import itertools
    import os
    dirs = ["c:\\usr", "c:\\temp"]
    subs = list(itertools.chain(*[os.listdir(d) for d in dirs]))
    print subs
    

    itertools.chain()。 返回迭代器,因此传递到 list() .

        10
  •  3
  •   Vestel    15 年前

    谷歌给我带来了下一个解决方案:

    def flatten(l):
       if isinstance(l,list):
          return sum(map(flatten,l))
       else:
          return l
    
        11
  •  2
  •   asu    7 年前

    你可以使用 pyxtension :

    from pyxtension.streams import stream
    stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)
    
        12
  •  1
  •   Vinod Kumar    7 年前
    def flat_list(arr):
        send_back = []
        for i in arr:
            if type(i) == list:
                send_back += flat_list(i)
            else:
                send_back.append(i)
        return send_back
    
        13
  •  0
  •   Baum mit Augen    9 年前
    If listA=[list1,list2,list3]
    flattened_list=reduce(lambda x,y:x+y,listA)
    

    这就行了。