web-dev-qa-db-ja.com

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はリストのリストをくれますが、本当にリストが欲しいです

64
Steve Cooper

単一のリスト内包でネストされた反復を持つことができます:

[filename for path in dirs for filename in os.listdir(path)]
95
Ants Aasma
>>> listOfLists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, listOfLists)
[1, 2, 3, 4, 5, 6]

Itertoolsソリューションはこれよりも効率的だと思いますが、これは非常にPython的であり、単一のリスト操作のためだけにライブラリをインポートする必要がなくなります。

62
Julian

itertoolsのレシピ: で良い答えを見つけることができます

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

(注:Python 2.6+)が必要です)

49
rob

質問は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を使用します。

23
Wai Yip Tung

あなたはただ簡単にすることができます:

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

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

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

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

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

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

(ただし、Antsの答えは優れています。彼にとっては+1です)

7
RichieHindle

次のように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()に渡されます。

4
Steef

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

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

pyxtension を使用できます。

from pyxtension.streams import stream
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)
2
asu
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
Vinod Kumar
If listA=[list1,list2,list3]
flattened_list=reduce(lambda x,y:x+y,listA)

これで十分です。

0
Prabhudatta Das