2

最近、誰かがリストを繰り返しながらリストを変更することの偽物について私に尋ねてきました。彼らは、動作が望ましい場合の可能なユースケースとして、次のシナリオ(より良い例で更新しました)を提示しました。

>>> jersey_numbers = [4, 2, 3, 5, 1]  # list of places in a race
>>> for jersey_number in jersey_numbers:
        if jersey_number == 2:  # disqualify jersey number 2 for a false start
            t.remove(jersey_number)
>>> t
[4, 3, 5, 1]  # jersey number 3 is now in second place

この動作は、このようなユースケースで使用するのに十分規則的ですか?

4

6 に答える 6

7

リストからアイテムを削除すると、リスト内のすべてがシフトオーバーします...

[1, 2, 3, 4, 5]
#remove   ^
[1, 2, 3, 5]

オブジェクトを反復処理しているときにこれを行い、削除したいアイテムが隣接している場合、最初のアイテムを削除すると、2番目のアイテムが代わりにシフトします。forループは、値を取得するリスト内の位置をインクリメントし続けます。これにより、削除したアイテムの代わりに、ぶつかった値がスキップされます。

ここにリファレンスがあります-これが十分に文書化された動作であることを私たち全員が知っているので:)

于 2013-01-25T18:23:43.003 に答える
5

代わりに使用する必要があるのは次のとおりです。

t = filter(None, t)  # or
t = [x for x in t if x]

または、条件が実際により複雑な場合:

t = filter(lambda x: x != something, t)  # or
t = [x for x in t if x != something]

ところで、remove最初に一致する要素を削除します。これは、必ずしもx現在指している要素ではありませんが、単純な場合の動作は同等です。

[1,0,0,2]何が起こるかというと、リストを反復している間、要素を削除し、イテレータはそれを認識していませんが、リストが次のようになっているとしましょう。

  • イテレータは1、変更なし、次の位置にあります
  • イテレータはにあり、最初のもの0を削除し0、変更されたサイズをリストします。これで、イテレータは2番目のゼロを指します。
  • 2イテレータは、変更なしを指します

実際、最初のアルゴリズムは1秒おきにゼロを削除します。

2番目のアルゴリズムは機能しないはずです。機能すると言った場合、おそらく十分にテストしていません。

于 2013-01-25T18:32:22.140 に答える
4

間違いは、リストを繰り返しながら変更していることです。これは期待どおりに動作しません(現在の要素を削除すると、次の要素がスキップされます)。

方法は次のとおりです。

In [18]: t = [5.0, 5.0, 5.0, 4.0, 0.0, 5.0, 0.0, 3.0, 5.0, 5.0, 0.0, 0.0, 4.0, 5.0, 0.0, 5.0, 4.0, 5.0, 3.0, 3.0, 5.0, 5.0, 5.0, 5.0]

In [19]: t[:] = [val for val in t if val != 0]
于 2013-01-25T18:20:33.990 に答える
2

リストを変更しているため、リストの浅いコピーを反復処理する必要があります。これにより、反復中に一部の項目が失われる可能性があります。

あなたがしていることにfilter()は、良い選択です。

filter(lambda x:x != 0.0,t)

浅いコピーの使用:

In [7]: t = [5.0, 5.0, 5.0, 4.0, 0.0, 5.0, 0.0, 3.0, 5.0, 5.0, 0.0, 0.0, 4.0, 5.0, 0.0, 5.0, 4.0, 5.0, 3.0, 3.0, 5.0, 5.0, 5.0, 5.0]

In [8]: for x in t[:]:   # a shallow copy of t
    if x==0.0:
        t.remove(x)

In [9]: 0.0 in t
Out[9]: False
于 2013-01-25T18:25:38.367 に答える
0
t = [e for e in t if e != 0.0]
于 2013-01-25T18:23:52.567 に答える
0

@mgilsonが言ったように、0.0値を削除すると、2番目の値0.0が代わりに使用され、見落とされました。

浅いコピーを繰り返し処理して、元のコピーから削除することができます。

 >>> t = [1, 2, 3, 3, 3, 4, 5]
 >>> for value in t[:]:
         if value == 3:
             t.remove(value)
 >>> t
 [1, 2, 4, 5]
于 2013-01-25T18:27:19.180 に答える