web-dev-qa-db-ja.com

Pythonの多くのリストの連結

次のような関数があるとします。

def getNeighbors(vertex)

これは、指定された頂点に隣接する頂点のリストを返します。今、私は隣人のすべての隣人のリストを作成したいと思います。私はそれを次のようにします:

listOfNeighborsNeighbors = []
for neighborVertex in getNeighbors(vertex):
    listOfNeighborsNeighbors.append(getNeighbors(neighborsVertex))

それを行うためのよりPython的な方法はありますか?

36
Björn Pollex
[x for n in getNeighbors(vertex) for x in getNeighbors(n)]

または

sum(getNeighbors(n) for n in getNeighbors(vertex), [])

いつものように、itertoolsモジュールにはソリューションが含まれています:

>>> l1=[1, 2, 3]

>>> l2=[4, 5, 6]

>>> l3=[7, 8, 9]

>>> import itertools

>>> list(itertools.chain(l1, l2, l3))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
57
Jochen

リストの追加は+とsum()で行うことができます:

>>> c = [[1, 2], [3, 4]]
>>> sum(c, [])
[1, 2, 3, 4]
36
Sjoerd

速度が重要な場合は、これを使用することをお勧めします。

_from operator import iadd
reduce(iadd, (getNeighbors(n) for n in getNeighbors(vertex)))
_

このコードのポイントは、リスト全体を_list.extend_で連結することです。リスト内包表記では、_list.append_を呼び出す場合と同様に、1つのアイテムを1つずつ追加します。これにより、オーバーヘッドが少し節約され、前者(私の測定によると)は約3倍速くなります。 (iadd演算子は通常_+=_として記述され、_list.extend_と同じことを行います。)

リスト内包表記(Ignacioによる最初のソリューション)を使用することは、通常は依然として正しい方法であり、読みやすくなっています。

ただし、sum(..., [])は2次時間で実行されるため、絶対に使用しないでください。 多数リスト(100以上)の場合、これは非常に非現実的です。

13
emu

速度で並べ替え:

list_of_lists = [[x,1] for x in xrange(1000)]

%timeit list(itertools.chain(*list_of_lists))
100000 loops, best of 3: 14.6 µs per loop

%timeit list(itertools.chain.from_iterable(list_of_lists))
10000 loops, best of 3: 60.2 µs per loop

min(timeit.repeat("ll=[];\nfor l in list_of_lists:\n ll.extend(l)", "list_of_lists=[[x,1] for x in xrange(1000)]",repeat=3, number=100))/100.0
9.620904922485351e-05

%timeit [y for z in list_of_lists for y in z]
10000 loops, best of 3: 108 µs per loop

%timeit sum(list_of_lists, [])
100 loops, best of 3: 3.7 ms per loop
11
Yariv

_itertools.chain_アプローチは線形時間で実行されるため(sum(...)は4次時間で実行されます)、@ Jochenは動的な長さのリストを処理する方法を示していません。 OPの質問に対する解決策を次に示します。

_import itertools
list(itertools.chain(*[getNeighbors(n) for n in getNeighbors(vertex)]))
_

Iterableで十分であれば、list(...)呼び出しを取り除くことができます。

2
renadeen

。extend()(定位置で更新)をsum()(毎回新しいオブジェクト)の代わりにreduceと組み合わせて使用​​する方が効率的ですが、テストするのが面倒ですそれ :)

mylist = [[1,2], [3,4], [5,6]] 
reduce(lambda acc_l, sl: acc_l.extend(sl) or acc_l, mylist)
0
realmaniek