web-dev-qa-db-ja.com

Pythonでn回繰り返される単一項目のリストを作成する

私はリスト内包表記がこれを行うことを知っています、しかし私はもっともっと短い(そしてもっとPythonic?)アプローチがあるかどうか疑問に思いました。

さまざまな長さの一連のリストを作成したいです。各リストは、同じ要素eを含み、n回繰り返されます(n =リストの長さ)。せずにリストを作成する方法

[e for number in xrange(n)]

リストごとに?

420
chimeracoder

あなたはまた書くことができます:

[e] * n

Eが例えば空リストの場合、n個の独立した空リストではなく、同じリストへのn個の参照を持つリストが得られます。

性能試験

一見すると、それは と思われる その繰り返しはn個の同一の要素を持つリストを作成する最も速い方法です:

>>> timeit.timeit('itertools.repeat(0, 10)', 'import itertools', number = 1000000)
0.37095273281943264
>>> timeit.timeit('[0] * 10', 'import itertools', number = 1000000)
0.5577236771712819

しかし、待ってください - それは公正なテストではありません...

>>> itertools.repeat(0, 10)
repeat(0, 10)  # Not a list!!!

関数itertools.repeatは実際にはリストを作成しません、それはあなたが望むならリストを作成するのに使用できるオブジェクトを作成するだけです!もう一度試してみましょう。ただし、リストに変換します。

>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233

もしリストが欲しいのなら、[e] * nを使ってください。要素を遅延して生成したい場合はrepeatを使用してください。

629
Mark Byers
>>> [5] * 4
[5, 5, 5, 5]

繰り返される項目がリストの場合は注意してください。リストは複製されません。すべての要素が同じリストを参照します。

>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
122
gaefan

Pythonでn回繰り返される単一項目のリストを作成する

不変アイテム

None、文字列、タプル、またはフリーズのような不変アイテムの場合は、次のようにします。

[e] * 4

これは、リスト内の不変アイテム(文字列、タプル、frozensetなど)でのみ使用するのが最も良いことに注意してください。それらはすべて、メモリ内の同じ場所にある同じアイテムを指すためです。 1対1のマッピングを指定する必要がないように、すべての文字列のスキーマを使用してテーブルを作成する必要がある場合は、これを頻繁に使用します。

schema = ['string'] * len(columns)

可変アイテム

私は長い間Pythonを使ってきましたが、可変インスタンスを使って上記のようなユースケースを見たことがありません。代わりに、可変の空のリスト、集合、または辞書を取得するには、次のようにします。

list_of_lists = [[] for _ in columns]

この場合、アンダースコアは単なる使い捨ての変数名です。

番号しかない場合は、次のようになります。

list_of_lists = [[] for _ in range(4)]

_はそれほど特別なものではありませんが、変数を使用し、他の名前を使用するつもりがない場合、コーディング環境スタイルチェッカーはおそらく文句を言います。


可変項目で不変メソッドを使用する際の注意事項

可変オブジェクトでこれを行うことに注意してください 、あなたがそれらの1つを変更すると、それらはすべて 同じ オブジェクトであるためすべて変更されます。

foo = [[]] *4
foo[0].append('x')

fooは次を返します。

[['x'], ['x'], ['x'], ['x']]

しかし不変オブジェクトでは、オブジェクトではなく参照を変更するのでそれを機能させることができます。

>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]

>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]

しかし、ここでもまた可変オブジェクトはこれには向いていません。インプレース操作は参照ではなくオブジェクトを変更するからです。

l = [set()] * 4
>>> l[0] |= set('abc')    
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]
55
Aaron Hall

Itertoolsにはそのための機能があります。

import itertools
it = itertools.repeat(e,n)

もちろんitertoolsはあなたにリストの代わりにイテレータを与えます。 [e] * nはあなたにリストを与えます、しかし、あなたがそれらのシーケンスをどうするかによって、itertoolsバリアントははるかに効率的になることができます。

23
Jochen Ritzel

他の人が指摘したように、可変オブジェクトに*演算子を使用すると参照が重複するため、1つを変更するとそれらすべてが変更されます。可変オブジェクトの独立したインスタンスを作成したい場合は、xrange構文がこれを実行するための最もPythonicの方法です。決して使用されない名前付き変数を持つことに悩まされているなら、あなたは無名アンダースコア変数を使うことができます。

[e for _ in xrange(n)]
10
W.P. McNeill
[e] * n

うまくいくはず

7
Mad Scientist