被链枚举困惑

时间:2013-02-11 20:28:19

标签: python

我想收集子目录列表中的所有头文件。但是,如果我这样做

from glob import glob
from itertools import chain

subDirs = ['FreeRTOS', 'Twig']
for each in chain(glob(eachDir+'/*.h') for eachDir in subDirs):
  print each

我得到的是

['FreeRTOS/croutine.h', 'FreeRTOS/FreeRTOS.h', 'FreeRTOS/FreeRTOSConfig.h', 'FreeRTOS/list.h', 'FreeRTOS/mpu_wrappers.h', 'FreeRTOS/portable.h', 'FreeRTOS/portmacro.h', 'FreeRTOS/projdefs.h', 'FreeRTOS/queue.h', 'FreeRTOS/semphr.h', 'FreeRTOS/StackMacros.h', 'FreeRTOS/task.h', 'FreeRTOS/timers.h']
['Twig/twig.h']

但我想看到的是

'FreeRTOS/croutine.h'
'FreeRTOS/FreeRTOS.h'
'FreeRTOS/FreeRTOSConfig.h'
'FreeRTOS/list.h'
'FreeRTOS/mpu_wrappers.h'
'FreeRTOS/portable.h'
'FreeRTOS/portmacro.h'
'FreeRTOS/projdefs.h'
'FreeRTOS/queue.h'
'FreeRTOS/semphr.h'
'FreeRTOS/StackMacros.h'
'FreeRTOS/task.h'
'FreeRTOS/timers.h'
'Twig/twig.h'

我认为这就是链()会为我做的事情。我错过了什么?

2 个答案:

答案 0 :(得分:3)

我认为您正在寻找itertools.chain.from_iterable

import os
import glob
import itertools

for each in itertools.chain.from_iterable(
        glob.glob(os.path.join(eachDir,'/*.h')) 
        for eachDir in subDirs):
    print each

它可迭代迭代的迭代:

In [6]: import itertools as IT
In [7]: list(IT.chain.from_iterable([['a', 'b', 'c'], [1, 2, 3]]))
Out[7]: ['a', 'b', 'c', 1, 2, 3]

答案 1 :(得分:0)

可能比unutbu的答案慢,但这也有效:

import collections
def flattenIter(l):
    """
        Iterator that flattens a list by one each iteration
        To get a fully flattened list of L do:
            list(flattenIter(L))
    """
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flattenIter(el):
                yield sub
        else:
            yield el

请注意,与unutbu的答案相比,这会使列表中的任何数量的列表变得扁平化而不是他的方法。示例:

print list(IT.chain.from_iterable([['a', 'b', 'c'], [1, 2, 3],"aap",["beer",[1]]]))
# ['a', 'b', 'c', 1, 2, 3, 'a', 'a', 'p', 'beer', [1]]
print list(flattenIter([['a', 'b', 'c'], [1, 2, 3],1,"aap",["beer",[1]]]))
# ['a', 'b', 'c', 1, 2, 3, 1, 'aap', 'beer', 1]

与unutbu的答案相同'out'。

In : list(flattenIter([['a', 'b', 'c'], [1, 2, 3]]))
Out: ['a', 'b', 'c', 1, 2, 3]

这是与unutbu版本的速度比较:

import timeit
import collections
import time
import itertools as IT

class Timer:
    def __enter__(self):
        self.start = time.clock()
        return self

    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

def flattenIter(l):
    """
        Iterator that flattens a list by one each iteration
        To get a fully flattened list of L do:
            list(flattenIter(L))
    """
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flattenIter(el):
                yield sub
        else:
            yield el

with Timer() as t:
    for x in xrange(10000):
        list(IT.chain.from_iterable([['a', 'b', 'c'], [1, 2, 3]]))

print t.interval
# result: 0.0220727116414

with Timer() as t:
    for x in xrange(10000):
        list(flattenIter([['a', 'b', 'c'], [1, 2, 3]]))

print t.interval
# result: 0.147218201587

同时退房:

Making a flat list out of list of lists in Python

虽然它还有一些其他固体链接,但它被标记为重复。 ;)