1

私はPythonの初心者です。C++ (初心者向け) や JQuery など、他の言語を以前に学習したことがあります。しかし、Python でのループは非常に紛らわしいと思います。

さて、私は簡単な結果を達成したいと思います。プログラムは単語のリストをループし、最初の2 文字とリスト内の次の単語に一致する単語を削除します。

test = ['aac', 'aad', 'aac', 'asd', 'msc']
for i in range(len(test)):
    if test[i][0:2] == test[i+1][0:2]:
        test.remove(test[i])

# This should output only ['aac', 'asd', 'msc']
print test

上記のコードは、リストから'aac'とを削除する必要'aad'があります。しかし、実際には、これによりIndexError. さらに、私は望ましい結果を達成することができませんでした。説明していただけますか?

4

4 に答える 4

2

リストからアイテムを削除してrange(len(test))も、同じ値が保持されます。したがって、testリストにアイテムが残っていなくても、ループは進行中です。

私には2つの解決策があります:

  1. 必要なアイテムを新しいリストにコピーするため、削除する代わりに:

    test2 = test[i]
    

    そして、条件を逆にすることを忘れないでください。

  2. 逆方向にループします。このような:

    n = len(test)
    for i in range(n):
        j = n - i - 1
        if j > 1:
        if test[j][0:2] == test[j-1][0:2]:
            test.remove(test[j])
    

    または、マーティンが提案したように:

    n = len(test)
    for i in range(n-1, 0, -1):
        if i > 1:
        if test[i][0:2] == test[i-1][0:2]:
            test.remove(test[i])
    

それが役に立てば幸い!

PS私のばかげた、以前の答えでごめんなさい

于 2013-10-11T07:00:53.907 に答える
2

リストの開始長さまでの範囲をループしながら、リストの長さを変更しています。リストから 1 つの項目を削除すると、最後のインデックスは無効になります。

現在のインデックスのリストから項目が削除されるため、残りのリスト インデックスはシフトします。index にあったものがi + 1indexiになり、ループ インデックスは役に立たなくなりました。

最後になりましたが、 の最後のインデックスまでループしていますが、それでもtestアクセスしようとしています。test[i + 1]リストから要素を削除していなくても、そのインデックスは存在しません。

ループを使用して、whileやりたいことを達成できます。

test = ['aac', 'aad', 'aac', 'asd', 'msc']
i = 0
while i < len(test) - 1:
    if test[i][:2] == test[i+1][:2]:
        del test[i]
        continue
    i += 1

ループの反復ごとに新しいi長さに対してテストされ、削除された要素がない場合にのみインクリメントされます。反復ごとにテストする必要があるため、ループの長さから 1 を引いた長さに制限されていることに注意してください。itest[i + 1]

del test[i];を使用していることに注意してください。削除する値を再度検索するためにリストをスキャンする必要はありません。これは、値がリストに複数回表示され、後のインスタンスのみを削除する必要がある場合にも、微妙なバグにつながる可能性があります。たとえば、['aac', 'foo', 'aac', 'aad']結果は['aac', 'foo', 'aad']ではなく ['foo', 'aac', 'aad']test.remove(test[i])なります。

デモ:

>>> test = ['aac', 'aad', 'aac', 'asd', 'msc']
>>> i = 0
>>> while i < len(test) - 1:
...     if test[i][:2] == test[i+1][:2]:
...         del test[i]
...         continue
...     i += 1
... 
>>> test
['aac', 'asd', 'msc']

リスト内包表記を使用して、縮小リストの問題を回避できます。

>>> [t for i, t in enumerate(test) if i == len(test) - 1 or t[:2] != test[i + 1][:2]]
['aac', 'asd', 'msc']

どちらの方法でも、入力リストを 1 回ループするだけで済みます。

于 2013-10-11T07:13:21.710 に答える
1

他の人が言ったように、アイテムを削除するとリストが短くなり、インデックス エラーが発生します。

元の質問に沿って維持します。list.remove() を使用してアイテムを削除しようとしている場合は、見つかったアイテムをリストに追加してから、それらを繰り返し処理して、次のように元のリストから削除できます。

# Set up the variables
test = ['aac', 'aad', 'aac', 'asd', 'msc']
found = []
# Loop Over the range of the lenght of the set
for i in range(len(test)):
    try:
        if test[i].startswith(test[i+1][0:2]):
            found.append(test[i])  # Add the found item to the found list
    except IndexError: # You'll hit this when you do test[i+1]
        pass

# Remove the Items at this point so you don't cause any issues
for item in found:
    test.remove(item)  # If an item has been found remove the first instance

# This sholuld output only ['aac', 'asd', 'msc']
print test

編集:

Martins のコメントによると、削除する必要がある項目の 2 番目のリストを作成する必要はありません。代わりに、次のように削除する必要のない項目のリストを作成できます。

# Set up the variables
test = ['aac', 'aad', 'aac', 'asd', 'msc']
found = []

# Loop Over the range of the lenght of the set
for i in range(len(test)):
    try:
        if not test[i].startswith(test[i+1][0:2]):
            found.append(test[i])  # Add the found item to the found list
    except IndexError: # You'll hit this when you do test[i+1]
        found.append(test[i]) # If there is no test[i+1], test[i] must be cool.


# This sholuld output only ['aac', 'asd', 'msc']
print found
于 2013-10-11T07:27:52.817 に答える
0

for i in range(len(test))の有効なインデックスのリストを提供しますtesttestただし、ループ内でアイテムを削除し続けると、 のサイズがtest縮小し、元は有効だったインデックスの一部が無効になります。

あなたがしていることは次のようなものです:

L = range(len(test))
for i in L:
  if condition:
    # remove something from test <- the size of test has changed.
                                 # L[-1] is no longer a valid index in test

代わりにできることは、削除したいもののインデックスを蓄積し、後でそれらを削除することです。

deleteThese = set()
for i,item in enumerate(test[:-1]):
  if item[0:2] == test[i+1][0:2]:
    deleteThese.add(i)
test = [item for i,item in enumerate(test) if i not in deleteThese]

出力:

In [70]: test = ['aac', 'aad', 'aac', 'asd', 'msc']

In [71]: %paste
deleteThese = set()
for i,item in enumerate(test[:-1]):
  if item[0:2] == test[i+1][0:2]:
    deleteThese.add(i)
test = [item for i,item in enumerate(test) if i not in deleteThese]

## -- End pasted text --

In [72]: test
Out[72]: ['aac', 'asd', 'msc']
于 2013-10-11T07:12:42.997 に答える