91

彼ら。私は問題に対する最も洗練された解決策を見つけようとしていますが、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は私にリストのリストをくれますが、私は本当にリストが欲しいです。

4

14 に答える 14

133

単一のリスト内包表記でネストされた反復を使用できます。

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

これは(少なくとも機能的には)次のものと同等です。

filenames = []
for path in dirs:
    for filename in os.listdir(path):
        filenames.append(filename)
于 2009-07-02T23:32:56.933 に答える
88
>>> from functools import reduce
>>> listOfLists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, listOfLists)
[1, 2, 3, 4, 5, 6]

itertools ソリューションはこれよりも効率的だと思いますが、これは非常に Pythonic に感じます。

Python 2 では、単一のリスト操作のためだけにライブラリをインポートする必要がなくなります (reduceが組み込まれているため)。

于 2010-01-17T18:32:30.687 に答える
62

itertools のレシピで適切な答えを見つけることができます。

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

(注: Python 2.6 以降が必要です)

于 2009-07-02T22:50:47.487 に答える
32

提案された質問flatmap。いくつかの実装が提案されていますが、中間リストを作成する必要がない場合があります。イテレータに基づく実装の 1 つを次に示します。

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ます。

于 2013-11-17T23:07:11.797 に答える
19

あなたは簡単に行うことができます:

subs = []
for d in dirs:
    subs.extend(os.listdir(d))
于 2009-07-02T23:37:11.713 に答える
17

通常の加算演算子を使用してリストを連結できます。

>>> [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がこのソリューションで不必要にたくさんの小さなリストを構築してガベージコレクションするのは正しいと思います。したがって、関数型プログラミングに慣れている場合は、非常にシンプルで簡潔であると言えます:-)

于 2009-07-03T12:47:57.377 に答える
11
import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y

itertools は python2.3 以降で動作します

于 2012-11-21T16:48:02.583 に答える
9
subs = []
map(subs.extend, (os.listdir(d) for d in dirs))

(しかし、アリの答えはより良いです;彼にとっては+1)

于 2009-07-02T22:48:38.647 に答える
4

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()ます。

于 2009-07-02T22:47:52.797 に答える
2

Google は私に次の解決策をもたらしました。

def flatten(l):
   if isinstance(l,list):
      return sum(map(flatten,l))
   else:
      return l
于 2009-07-02T22:52:51.990 に答える