понимание списка Python; сжатие списка списков?

ребята. Я пытаюсь найти наиболее элегантное решение проблемы и спрашиваю себя, есть ли в Python что-то встроенное для того, что я пытаюсь сделать.

Что я делаю, так это У меня есть список,Aи у меня есть функцияf который берет элемент и возвращает список. Я могу использовать понимание списка, чтобы преобразовать все вA вот так;

[f(a) for a in A]

Но это возвращает список списков;

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

Что я действительно хочу, так это получить плоский список;

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

Теперь, у других языков есть это; он традиционно называетсяflatmap на функциональных языках программирования, и .Net называет этоSelectMany, Python имеет что-нибудь подобное? Есть ли удобный способ отобразить функцию на список и сгладить результат?

The actual problem I'm trying to solve is this; starting with a list of directories, find all the subdirectories. so;

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

currentliy gives me a list-of-lists, but I really want a list.

Ответы на вопрос(13)

Ты можешь использоватьpyxtension:

from pyxtension.streams import stream
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(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

Вы можете объединять списки, используя обычный оператор сложения:

>>> [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]

Edit: Я только что увидел критику в комментариях кдругой ответ и я думаю, что это правильно, что Python будет без необходимости собирать и собирать мусор с помощью множества небольших списков с этим решением. Поэтому самое лучшее, что можно сказать об этом, это то, что он очень прост и лаконичен, если вы привыкли к функциональному программированию :-)

If listA=[list1,list2,list3]
flattened_list=reduce(lambda x,y:x+y,listA)

Это подойдет.

Предложенный вопрос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.

import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y

itertools будет работать с python2.3 и выше

>>> listOfLists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, listOfLists)
[1, 2, 3, 4, 5, 6]

Я предполагаю, что решение itertools более эффективно, чем это, но это выглядит очень питонно и позволяет избежать импорта библиотеки только ради одной операции со списком.

subs = []
map(subs.extend, (os.listdir(d) for d in dirs))

(но ответ Антса лучше; +1 для него)

Вы могли бы просто сделать просто:

subs = []
for d in dirs:
    subs.extend(os.listdir(d))
Решение Вопроса

Вы можете иметь вложенные итерации в понимании одного списка:

[filename for path in dirs for filename in os.listdir(path)]

Google принес мне следующее решение:

def flatten(l):
   if isinstance(l,list):
      return sum(map(flatten,l))
   else:
      return l

Вы можете найти хороший ответ вitertools & APOS; рецепты:

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

(Примечание: требуется Python 2.6+)

Вы могли бы попробовать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().

Ваш ответ на вопрос