2011-01-20 1 views
3

私は約200,000個以上のオブジェクトのリストを持っています。それぞれがファイルを表しています(実際にはファイルの内容は保持せず、完全なパス名と日付だけです)。大きなリストを調べようとしたときのPython IndexError

私が書いているプログラムは、ユーザー提供の日付範囲によっては、これらのファイルのサブセットをコピーします。私は最初、(globモジュール付き)ソースディレクトリ内のすべてのファイルのリストを作成し、私のファイル・表現クラスのインスタンスを作成し、そのように、リストにそのインスタンスを追加します。

for f in glob.glob(srcdir + "/*.txt"): 
    LOG_FILES.append(LogFile(f)) 

を今、ファイルのコピーを素早く保ち、コードブロックをきれいにするために、日付範囲内に収まらないLogFileオブジェクトを削除します。

for i in xrange(0, len(LOG_FILES)): 
    if LOG_FILES[i].DATE < from_date or LOG_FILES[i].DATE > to_date: 
     del(LOG_FILES[i]) 

その後、私は、リストに残っているファイルをコピーすることができます

for logfile in LOG_FILES: 
    os.copy(logfile.PATH, destdir) 

問題がfor i in xrange...例で発生します。iの値が63792に到達したとき、私ははIndexErrorを投げます。

IndexError: list index out of range. 

EDITすばやくご回答いただきありがとうございます。今私はそれについて考えている、それは私の愚かな監督だった。もう一度、みなさん、ありがとう。 :)

+2

ではなく、反復処理中のシーケンスを変更するLogFile(f).DATEです。 –

+0

SQLで日付範囲を簡単に照会できます。アプリケーションがユーザーに配布されることを意図しているのであれば、おそらくデータベースが最適です。ちょうどアイデア。 – krs1

+0

ありがとうございましたkrsですが、配布用ではありません - 特定のイベントのログを作成する古くからの古風なシステム(私は最終的に書き直す予定です)のログファイルのセットを取得するだけです。 – nesv

答えて

2

[編集]おっと、私は "<"と ">"を逆転して "等号"記号を追加するのを忘れました。

LOG_FILES = [LogFile(f) for f in glob.glob(srcdir + "/*.txt") 
         if from_date <= f.DATE <= to_date] 

これは、LOG_FILESの完全な初期化を置き換えることができます。リストの理解です(あなたがそれを列挙するまで評価されないようにしたい場合は、[]を()と置き換えることで)ジェネレータにすることができれば、それはあなたが何をしているかによってより効率的になるでしょう。

あなたはそれが許可されていない列挙中に、コレクションを編集するため、これを実行する必要があります(上記far more eloquentの回答を参照してください)

あなたはこのように、上記の式を読むことができます:。。

「リスト(または可算を作成) 'glob.glob(...)'内の各fに対して 'f'が渡されたときだけ、 'if'文が真である場合にのみLogFileの結果を返します。

参照:そのリンクのThe List Comprehensionセクション。

+0

[1比較が多すぎる](http://stackoverflow.com/questions/101268/hidden-features-of-python/101945#101945) – SilentGhost

+0

それを指摘してくれてありがとう。私はC++やC#からPythonに移行するときにいつもその部分を失います。:) – Crisfole

+0

不要なリストの作成を避けるために 'glob.iglob'を使うこともできます。 – SilentGhost

1

上限を固定して配列をループして同時に要素を削除する場合は、はインデックスエラーを生成します。コピーをループするか、動的インデックスを使用する必要があります。

limit, i = len(LOG_FILES), 0 
while i < limit: 
    if LOG_FILES[i].DATE < from_date and LOG_FILES[i].DATE > to_date: 
     del(LOG_FILES[i]) 
     limit -= 1 
    else: 
     i += 1 
7

the docsから::(これはのみ変更可能なシーケンスのために発生する可能性がループ内で反復処理されている順序を変更することは安全ではありません

あなたは、配列が大きい述べたので、我々は後者を使いますリストなどのタイプ)。(たとえば、選択した項目を複製するために)反復処理中のリストを変更する必要がある場合は、コピーを反復処理する必要があります。あなたのケースでは

、私は実際にファイルのあなたの大きなリストの不要なコピーを作成することを避けるために、ジェネレータ式とitertools.ifilterを使用してに探してお勧めしたいです。

+0

ここにあるドキュメントから引用されたコメントは正しいですが、より良い説明には*なぜ*安全でないのが含まれていると思います –

+0

あなたは正しいです、あなたの答えは良い説明、+1です。ありがとう! –

3

del()は、そのインデックスでリストのエントリを削除し、リストを再注文しているという問題があります。

たとえば、5つのアイテムがリストにあり、3番目のインデックスでdel()を呼び出すと、リストの内容がシフトダウンされ、別の要素が3番目のインデックスになります。

list = [1,2,3,4,5] 
del(list[2]) 
print list  # outputs [1, 2, 4, 5] 
print list[2] # outputs 4 

あなたはリストから一つだけのアイテムを削除した場合でも、リストの元のサイズに0からループしているので、あなたは最終的にはもはやリストに含まれているインデックスに到着します。

もっと簡単な方法は、アイテムを追加するときにリストをフィルタすることです。

for f in glob.glob(srcdir + "/*.txt"): 
    lf = LogFile(f) 
    if lf.DATE < from_date and lf.DATE > to_date: 
     LOG_FILES.append(lf) 

これはおそらくもっとpythonicになる可能性がありますが、ポイントを取得するのに十分な程度に読みやすくする必要があります。

1

またfilterを使用することができます。

LOG_FILES = filter(lambda log_file: log_file.DATE < from_date and \ 
            log_file.DATE > to_date, LOG_FILES) 
0

1)端からリストの先頭に、リスト内の反復中の要素を削除する問題

LOG_FILES = [ 1,2,30,2,5,8,30,3,2,37,22,30,27,30,4 ] 

print LOG_FILES 

L = len(LOG_FILES)-1 
for i,x in enumerate(LOG_FILES[::-1]): 
    print i,L-i,' ',LOG_FILES[L-i],x 
    if x>15: 
     del LOG_FILES[L-i] 

print LOG_FILES 

結果を溶解

[1, 2, 30, 2, 5, 8, 30, 3, 2, 37, 22, 30, 27, 30, 4] 
0 14 4 4 
1 13 30 30 
2 12 27 27 
3 11 30 30 
4 10 22 22 
5 9 37 37 
6 8 2 2 
7 7 3 3 
8 6 30 30 
9 5 8 8 
10 4 5 5 
11 3 2 2 
12 2 30 30 
13 1 2 2 
14 0 1 1 
[1, 2, 2, 5, 8, 3, 2, 4] 

2) LOG_FILES [i]はログファイルであるため、

LOG_FILES = [LogFile(f) for f in glob.glob(srcdir + "/*.txt") 
      if f.DATE >= from_date and f.DATE <= to_date] 

以来

for f in glob.glob(srcdir + "/*.txt"): 
    LOG_FILES.append(LogFile(f)) 

:ところで

if LOG_FILES[i].DATE < to_date and LOG_FILES[i].DATE > from_date : 

はCpfohlの答えに問題があります

if from_date < LOG_FILES[i].DATE < to_date: 
1

を書き込むことができます(f) そしてLOG_FILES [i] .DATEは、f.DATE

関連する問題