web-dev-qa-db-ja.com

リストをPythonの既知の数の要素に初期化する

今私はリストを使っていて、次のようなものを期待していました。

verts = list (1000)

代わりにarrayを使うべきですか?

222
Joan Venge

私にとって頭に浮かぶのは、次のとおりです。

verts = [None]*1000

しかし、あなたは本当にそれを事前に初期化する必要がありますか?

322
Steve Losh

誰もがこれをやりたいと思うのに苦労している理由がよくわからない - 固定サイズの初期化リストが欲しいと思うシナリオがいくつかある。そして、あなたは正しく配列がこれらの場合に賢明であると推測しました。

import array
verts=array.array('i',(0,)*1000)

Python以外の人にとっては、(0,)*1000という用語は1000個のゼロを含むTupleを作成しています。コンマはpythonに(0)をTupleとして認識させる。そうでなければ0として評価されるだろう。

私はリストの代わりにTupleを使いました。それらは一般的にオーバーヘッドが少ないからです。

69
FoxyLad

1つの明白でおそらく効率的でない方法は

verts = [0 for x in range(1000)]

これは簡単に2次元に拡張できることに注意してください。たとえば、10 x 100の「配列」を取得するには、次のようにします。

verts = [[0 for x in range(100)] for y in range(10)]
60
e-shy

固定サイズの配列を初期化したいのであれば、どのプログラミング言語でも実行可能です。プログラマーがbreakステートメントをwhile(true)ループに入れたいのではありません。特に、多くの動的計画法のアルゴリズムのように、要素が単に上書きされて単純に加減算されないのであれば、appendステートメントや要素が削除されていないかどうかをチェックしたくないでしょうまだオンザフライで初期化されています(それはたくさんのコードの紳士です)。

object = [0 for x in range(1000)]

これはプログラマーが達成しようとしていることのために働くでしょう。

30
Miko

@Steveはすでにあなたの質問に良い答えを出しています:

verts = [None] * 1000

警告:@Joachim Wuttkeが指摘したように、リストは不変要素で初期化されなければなりません。 [[]] * 1000は期待通りには動きません。なぜならあなたは1000個の同一のリストのリストを得るからです(Cの同じリストへの1000ポイントのリストに似ています)。 int、str、Tupleなどの不変のオブジェクトでもうまくいきます。

代替案

リストのサイズ変更は遅いです。次の結果はそれほど驚くべきことではありません。

>>> N = 10**6

>>> %timeit a = [None] * N
100 loops, best of 3: 7.41 ms per loop

>>> %timeit a = [None for x in xrange(N)]
10 loops, best of 3: 30 ms per loop

>>> %timeit a = [None for x in range(N)]
10 loops, best of 3: 67.7 ms per loop

>>> a = []
>>> %timeit for x in xrange(N): a.append(None)
10 loops, best of 3: 85.6 ms per loop

しかし、非常に大きなリストがなければ、サイズ変更はそれほど遅くありません。リストのサイズを変更しないように単一の要素(Noneなど)と固定長でリストを初期化する代わりに、リスト内包表記を使用してリストに正しい値を直接入力することを検討してください。例えば:

>>> %timeit a = [x**2 for x in xrange(N)]
10 loops, best of 3: 109 ms per loop

>>> def fill_list1():
    """Not too bad, but complicated code"""
    a = [None] * N
    for x in xrange(N):
        a[x] = x**2
>>> %timeit fill_list1()
10 loops, best of 3: 126 ms per loop

>>> def fill_list2():
    """This is slow, use only for small lists"""
    a = []
    for x in xrange(N):
        a.append(x**2)
>>> %timeit fill_list2()
10 loops, best of 3: 177 ms per loop

ナンプティとの比較

巨大なデータセットや、他の最適化されたライブラリの方がはるかに高速です。

from numpy import ndarray, zeros
%timeit empty((N,))
1000000 loops, best of 3: 788 ns per loop

%timeit zeros((N,))
100 loops, best of 3: 3.56 ms per loop
17
lumbric

あなたはこれをすることができます:

verts = list(xrange(1000))

それはあなたにサイズが1000個の要素のリストを与え、それは0-999の値で初期化されることが起こるでしょう。 listは新しいリストのサイズを決めるために__len__を最初にするので、それはかなり効率的であるべきです。

4
John Montgomery

この:

 lst = [8 for i in range(9)]

リストを作成し、要素は初期化されます8

でも、これ:

lst = [0] * 7

1つの要素を持つ7つのリストを作成します

0
Jutta

あなたは事前に初期化されたリストの代わりにdict型を使うことを検討するべきです。辞書検索のコストは小さく、任意のリスト要素にアクセスするコストに匹敵します。

そして、マッピングを使うとき、あなたは書くことができます:

aDict = {}
aDict[100] = fetchElement()
putElement(fetchElement(), fetchPosition(), aDict)

そしてputElement関数は任意の位置にitemを格納することができます。そして、あなたのコレクションが与えられたインデックスの要素を含んでいるかどうかをチェックする必要があるなら、書くのはもっとPythonicです:

if anIndex in aDict:
    print "cool!"

より:

if not myList[anIndex] is None:
    print "cool!"

後者はあなたのコレクションの本当の要素がNoneになることはできないと仮定しているので。そしてそれが起こるなら - あなたのコードは誤動作します。

そして、あなたがパフォーマンスを切実に必要としていて、それであなたがあなたの変数を事前に初期化し、そして可能な限り最速のコードを書くことを試みる理由 - あなたの言語を変えなさい。最速のコードはPythonで書くことはできません。代わりにCを試して、ラッパーを実装してPythonから事前初期化および事前コンパイルされたコードを呼び出すようにしてください。

0
Abgan