みんな。私は問題に対する最もエレガントな解決策を見つけようとしていますが、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はリストのリストをくれますが、本当にリストが欲しいです
単一のリスト内包でネストされた反復を持つことができます:
[filename for path in dirs for filename in os.listdir(path)]
>>> listOfLists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, listOfLists)
[1, 2, 3, 4, 5, 6]
Itertoolsソリューションはこれよりも効率的だと思いますが、これは非常にPython的であり、単一のリスト操作のためだけにライブラリをインポートする必要がなくなります。
itertoolsのレシピ: で良い答えを見つけることができます
def flatten(listOfLists):
return list(chain.from_iterable(listOfLists))
(注:Python 2.6+)が必要です)
質問は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では、map
の代わりにitertools.map
を使用します。
あなたはただ簡単にすることができます:
subs = []
for d in dirs:
subs.extend(os.listdir(d))
通常の加算演算子を使用してリストを連結できます。
>>> [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はこのソリューションで不必要に多くの小さなリストを作成し、ガベージコレクションします。したがって、それについて言える最も良いことは、関数型プログラミングに慣れている場合は非常にシンプルで簡潔であることです:-)
import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y
itertoolsはpython2.3以降で動作します
subs = []
map(subs.extend, (os.listdir(d) for d in dirs))
(ただし、Antsの答えは優れています。彼にとっては+1です)
次のように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()
に渡されます。
Googleは次の解決策をもたらしました。
def flatten(l):
if isinstance(l,list):
return sum(map(flatten,l))
else:
return l
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
If listA=[list1,list2,list3]
flattened_list=reduce(lambda x,y:x+y,listA)
これで十分です。