Вопрос по python – понимание списка Python; сжатие списка списков?

59

ребята. Я пытаюсь найти наиболее элегантное решение проблемы и спрашиваю себя, есть ли в 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   ответов
15

subs = []
for d in dirs:
    subs.extend(os.listdir(d))
Error: User Rate Limit Exceeded
47

itertools & APOS; рецепты:

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

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

Error: User Rate Limit Exceededthis answerError: User Rate Limit Exceededexternal blog post
3

def flatten(l):
   if isinstance(l,list):
      return sum(map(flatten,l))
   else:
      return l
Error: User Rate Limit Exceeded
0
If listA=[list1,list2,list3]
flattened_list=reduce(lambda x,y:x+y,listA)

Error: User Rate Limit Exceeded+Error: User Rate Limit Exceeded
2

pyxtension:

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

>>> [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 будет без необходимости собирать и собирать мусор с помощью множества небольших списков с этим решением. Поэтому самое лучшее, что можно сказать об этом, это то, что он очень прост и лаконичен, если вы привыкли к функциональному программированию :-)

Error: User Rate Limit Exceeded
1
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
10
import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y

3

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().

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

В общем, вы не можете сказать, что это плохое решение. Это зависит от того, является ли производительность даже проблемой. Просто лучше, если нет причин для оптимизации. Вот почему метод сокращения может быть наилучшим для многих проблем. Например, у вас есть медленная функция, которая создает список из нескольких сотен объектов. Вы хотите ускорить его, используя многопроцессорную обработку данных & map; функция. Таким образом, вы создаете 4 процесса и используете команду «Уменьшить до плоской карты». В этом случае функция уменьшения отлично работает и очень удобочитаема. Тем не менее, хорошо, что вы указываете, почему это может быть неоптимальным. Но это не всегда неоптимально.
@ Алекс: Хороший вопрос. Исправлена.
Использование Reduce (или Sum, которое экономит много символов и импорт ;-), потому что это просто неправильно - вы продолжаете бесполезно отбрасывать старые списки, чтобы создать новый для каждого d. У @Ants есть правильный ответ (умный @Steve, чтобы принять это!).
20

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.

86

[filename for path in dirs for filename in os.listdir(path)]
Error: User Rate Limit Exceeded
Хотя это умно, это трудно понять и не очень читабельно.
Error: User Rate Limit Exceeded
В действительности не отвечает на вопрос в том виде, в котором он был задан. Это скорее обходной путь, чтобы не столкнуться с проблемой в первую очередь. Что делать, если у вас уже есть список списков. Например, что если ваш список списков является результатом функции карты многопроцессорного модуля? Возможно, лучше всего решение itertools или сокращение.
Dave31415:[ item for list in listoflists for item in list ]
60
>>> listOfLists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, listOfLists)
[1, 2, 3, 4, 5, 6]

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

Error: User Rate Limit ExceededreduceError: User Rate Limit Exceededpandas, scipy или жеfunctools?
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededfunctoolsError: User Rate Limit Exceeded

Похожие вопросы