Python:n個のリストのリストを作成する最速の方法


97

だから私は空のリストのリストを作成する方法を考えていました:

[[],[],[]...]

Pythonがメモリ内のリストを処理する方法のため、これは機能しません。

[[]]*n

これは作成します[[],[],...]が、各要素は同じリストです:

d = [[]]*n
d[0].append(1)
#[[1],[1],...]

リスト内包のようなものが機能します:

d = [[] for x in xrange(0,n)]

しかし、これはループにPython VMを使用します。(Cで記述されていることを利用して)暗黙のループを使用する方法はありますか?

d = []
map(lambda n: d.append([]),xrange(0,10))

これは実際には遅いです。:(


1
実質的にこれよりも速いものがあれば、私は驚きd = [[] for x in xrange(0,n)]ます。あなたはPythonで明示的にループするか、Pythonの関数/ラムダを繰り返し呼び出す必要があります(これは遅いはずです)。しかし、誰かが私が間違っていることを示す何かを投稿することを期待しています:)。
MAK、2011

1
でこれらを測定したときtimeit、何を学びましたか?
S.Lott、2011

map(lambda x: [], xrange(n))リストの理解よりも遅いことを確認しました。
Andrew Clark

回答:


105

よりわずかに速いおそらく唯一の方法

d = [[] for x in xrange(n)]

です

from itertools import repeat
d = [[] for i in repeat(None, n)]

int毎回新しいオブジェクトを作成する必要はなく、私のマシンでは約15%高速です。

編集:NumPyを使用すると、Pythonループを回避できます

d = numpy.empty((n, 0)).tolist()

しかし、これは実際にはリスト内包よりも2.5倍遅いです。


いかがmap(lambda x:[], repeat(None,n))ですか?
PaulMcG 2011

3
@Paul:ラムダ式の関数呼び出しのオーバーヘッドが原因で、速度は再び遅くなります。
Sven Marnach、2011

Python 3では範囲が異なるので、これを更新すべきではないでしょうか
beruic

@beruic最初のコードブロックで質問のコードを引用しているだけなので、それを変更しても意味がありません。
Sven Marnach、

12

リスト内包表記は実際には明示的なループよりも効率的に実装され(関数の例についてdis出力を参照)、map方法は反復ごとに不透明な呼び出し可能オブジェクトを呼び出す必要があり、かなりのオーバーヘッドオーバーヘッドが発生します。

とにかく、[[] for _dummy in xrange(n)]それはそれを行う正しい方法であり、他のさまざまな方法の間のわずかな(存在する場合)速度の違いはどれも重要ではありません。もちろん、これを行うのにほとんどの時間を費やさない限り、その場合は、代わりにアルゴリズムに取り組む必要があります。どのくらいの頻度でこれらのリストを作成しますか?


5
_変数名としてはいけません!そうでなければ良い答え:)
Sven Marnach

11
@スヴェン:どうして?これは一般的に未使用の変数に使用されます(それがと呼ばれた場合i、私はそれが使用される場所を探します)。唯一の落とし穴は_、REPLでの最後の結果の保持を覆い隠してしまうことです。これは、2.xの場合で、リスト内包がリークする場合にのみ当てはまります。

それほど頻繁ではないので、先に進み、リスト内包表記を使用しました。人々が何を言わなければならないかを見ることは興味深いだろうと思った。私は、DyboxがPyConでforループの代わりにitertools.imapを使用してmd5ハッシュを不条理に大量に更新するのを見て、それ以来、Cループに少し夢中になっています。
munchybunch 2011

12
これを使用しない最も重要な理由は、人々を混乱させ、ある種の特別な構文であると人々に思わせる傾向があるためです。また_、インタラクティブインタープリタとの競合に加えて、一般的なgettextエイリアスとも競合します。変数がダミー変数であることを明確にしたい場合は、dummyではなくを呼び出します_
スヴェンマルナッハ、2011

12

ここに2つの方法があります。1つはスイートでシンプル(概念的)で、もう1つはよりフォーマルで、データセットを読み取った後、さまざまな状況で拡張できます。

方法1:概念

X2=[]
X1=[1,2,3]
X2.append(X1)
X3=[4,5,6]
X2.append(X3)
X2 thus has [[1,2,3],[4,5,6]] ie a list of lists. 

方法2:形式的で拡張可能

別の番号のリストのリストとしてリストを保存するもう1つのエレガントな方法-ファイルから読み取ります。(このファイルにはデータセットtrainが含まれています)Trainは、たとえば50行と20列のデータセットです。すなわち。Train [0]はcsvファイルの1行目を提供し、train [1]は2行目を提供します。ここで説明する変数である列0を除いて、50行のデータセットを1つのリストとして分離することに関心があるので、元の列車データセットから削除する必要があり、リストの後にリスト(つまり、リストのリスト)を拡大する必要があります。 。これを行うコードは次のとおりです。

説明変数のみに関心があるので、内部ループで「1」から読み取っていることに注意してください。そして、他のループでX1 = []を再初期化します。それ以外の場合、X2.append([0:(len(train [0])-1)])はX1を何度も書き換えます-その上、メモリ効率が向上します。

X2=[]
for j in range(0,len(train)):
    X1=[]
    for k in range(1,len(train[0])):
        txt2=train[j][k]
        X1.append(txt2)
    X2.append(X1[0:(len(train[0])-1)])

4

リストとリストのリストを作成するには、以下の構文を使用します

     x = [[] for i in range(10)]

これは1-dリストを作成し、それを初期化するために[[number]に数値を入れ、リストの長さをrange(length)に入れます

  • リストのリストを作成するには、以下の構文を使用します。
    x = [[[0] for i in range(3)] for i in range(10)]

これにより、リストのリストが10 * 3のディメンションと値0で初期化されます

  • 要素にアクセス/操作するには
    x[1][5]=value

2

だから私はいくつかの速度比較を行って最速の方法を得ました。リスト内包表記は確かに非常に高速です。接近する唯一の方法は、リストの構築中にバイトコードが実行されないようにすることです。私の最初の試みは以下の方法でした。

l = [[]]
for _ in range(n): l.extend(map(list,l))

(もちろん長さ2 ** nのリストを生成します)この構造は、短いリストと長い(100万)リストの両方について、timeitによると、リストの理解力の2倍の速度です。

2つ目の試みは、スターマップを使用してリストコンストラクターを呼び出すことでした。リストコンストラクターを最高速度で実行しているように見えますが、それでも速度は遅くなりますが、ごくわずかです。

from itertools import starmap
l = list(starmap(list,[()]*(1<<n)))

興味深いことに、実行時間はスターマップソリューションを遅くしているのは最終的なリスト呼び出しであることを示唆しています。これは、その実行時間がほぼ正確に以下の速度に等しいためです。

l = list([] for _ in range(1<<n))

3番目の試みは、list(())もリストを生成することに気付いたときに来たので、次のように簡単に試してみました。

l = list(map(list, [()]*(1<<n)))

しかし、これはスターマップの呼び出しよりも低速でした。

結論:スピードマニアのために:リスト内包表記を使用してください。必要な場合にのみ関数を呼び出します。ビルトインを使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.