大きなリストを調べようとするとPython IndexErrorが発生する

python
大きなリストを調べようとするとPython IndexErrorが発生する

約200 000以上のオブジェクトのリストがあり、各オブジェクトはファイルを表します(ただし、実際にはファイルの内容は保持されず、フルパス名と日付のみが保持されます)。

私が書いているプログラムは、ユーザーが指定した日付範囲に応じて、これらのファイルのサブセットをコピーします。 最初に、ソースディレクトリ内のすべてのファイルのリストを( `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.

何か案は?

*編集*迅速な対応ありがとうございました! 今考えてみると、それは私の側のばかげた見落としでした。 繰り返しますが、皆さん、ありがとうございます。 🙂

  3  0


ベストアンサー

_
ループ内で繰り返されるシーケンスを変更することは安全ではありません(これは、リストなどの可変シーケンスタイプに対してのみ発生します)。 繰り返し処理するリストを変更する必要がある場合(たとえば、選択したアイテムを複製するため)、コピーを繰り返し処理する必要があります。
_

あなたの場合、実際にジェネレータ式とhttp://docs.python.org/library/itertools.html#itertools.ifilter [itertools.ifilter]の使用を検討することをお勧めします。ファイルのリスト。

7


メソッドの問題は、http://docs.python.org/tutorial/datastructures.html#the-del-statement [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からリストの元のサイズまでループしているため、リストから1つのアイテムのみを削除した場合でも、最終的にはリストに含まれていないインデックスに到達します。

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

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にできるかもしれませんが、要点を理解するのに十分読みやすいはずです。

3


  • [編集] *おっと、「<」と「>」を反転し、「等号」記号を追加するのを忘れました。

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

これにより、LOG_FILESの初期化全体を置き換えることができます。 []を()に置き換えることにより、リスト内包表記です(列挙するまで評価されないジェネレーターにしたい場合)。 それはあなたがそれをどうするかに応じてより効率的かもしれません。

コレクションを列挙しながら編集することは許可されていないため、これを行う必要があります。 (上記、https://stackoverflow.com/questions/4752866/python-indexerror-when-trying-to-go-through-a-large-list/4752910#4752910 [はるかに雄弁]の回答を参照)。

上記の式は次のように読むことができます。

「 ‘glob.glob(…​)’の各fに対して ‘f’が渡された場合に、 ‘if’ステートメントがtrueの場合にのみ、LogFileの結果のリスト(または列挙可能)を作成します。 “

参照:そのリンクのhttp://docs.python.org/tutorial/datastructures.html [リスト内包表記]セクション。

2


上限が固定された配列をループし、同時に要素を削除する場合、インデックスエラーが発生します。 コピーをループするか、動的インデックスを使用する必要があります。 配列が大きいと述べたため、後者を使用します。

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

1


http://docs.python.org/library/functions.html#filter [filter]を使用することもできます。

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

1


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

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))

したがって、LOG_FILES [i]はLogFile(f)であり、LOG_FILES [i] .DATEはf.DATEではなくLogFile(f).DATEです。

1


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)ところで

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

書ける

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

0


タイトルとURLをコピーしました