Подтвердить что ты не робот

Понимание списков 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 есть что-то подобное? Есть ли опрятный способ сопоставить функцию над списком и сгладить результат?

Фактическая проблема, которую я пытаюсь решить, заключается в следующем; начиная со списка каталогов, найдите все подкаталоги. так;

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

currentliy дает мне список списков, но мне действительно нужен список.

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

Вы можете просто сделать прямо:

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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

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

Ответ 8

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

(но ответ Ants лучше, +1 для него)

Ответ 9

Вы можете попробовать 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

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

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

Ответ 11

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

Ответ 12

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

from pyxtension.streams import stream
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)

Ответ 13

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

Это сделает.