Eine Grube, die in Python-Listen und -Wörterbüchern oft betreten wird

Machen Sie es sich zur Gewohnheit, gemeinsam zu schreiben! Dies ist der 14. Tag meiner Teilnahme an der „Nuggets Daily New Plan·April Update Challenge“, klicken Sie hier, um die Details der Veranstaltung anzuzeigen .

[Einführung]: Wenn wir in Python einen Datensatz beim Durchlaufen eines Datensatzes ändern möchten, gibt es normalerweise viele Probleme.Wenn Sie beispielsweise die obige Operation für eine Liste ausführen, werden einige Daten ignoriert; Beim Durchlaufen eines Wörterbuchs können die Daten nicht geändert werden. Dieses Papier schlägt eine Vielzahl von Lösungen für diese Probleme vor.

Einführung

1. Über die Liste

1. Problembeschreibung

Wenn Sie in Python versuchen, einen Datensatz zu ändern, während Sie darüber iterieren, ist dies normalerweise in Ordnung. Z.B:


l = [3, 4, 56, 7, 10, 9, 6, 5]

for i in l:
    if not i % 2 == 0:
        continue
    l.remove(i)

print(l)
复制代码

Der obige Code durchläuft eine Liste von Zahlen und modifiziert die Liste l direkt, um alle geraden Zahlen zu entfernen. Die Ausgabe nach dem Ausführen ist jedoch:

[3, 56, 7, 9, 5]
复制代码

Moment mal! Die Ausgabe scheint nicht richtig zu sein. Das Endergebnis enthält immer noch eine gerade Zahl 56. Warum wurde diese Nummer nicht erfolgreich entfernt? Wir können versuchen, alle von der for-Schleife durchlaufenen Elemente auszudrucken, indem wir den folgenden Code ausführen:

l = [3, 4, 56, 7, 10, 9, 6, 5]

for i in l:
    print(i)
    if not i % 2 == 0:
        continue
    l.remove(i)

print(l)
复制代码

Die Ausgabe dieses Codes ist:

3
4
7
10
6
[3, 56, 7, 9, 5]
复制代码

Wie Sie der Ausgabe entnehmen können, scheint die for-Schleife nicht auf alle Elemente in der Liste zuzugreifen. Um zu verstehen, was die for-Schleife intern macht, können wir sie mit iter und next simulieren. Schauen Sie sich das folgende Beispiel an, in dem ich die ipython-Shell verwende, um den Code auszuführen:


In [1]: l = [3, 4, 56, 7, 10, 9, 6, 5]

In [2]: # 把列表变成一个迭代器

In [3]: it = iter(l)

In [4]: # 使用 next() 方法来模拟 for循环

In [5]: next(it)
Out[5]: 3

In [6]: next(it)
Out[6]: 4

In [7]: # 移除一个迭代器已经访问过的元素

In [8]: l.remove(3)

In [9]: next(it)
Out[9]: 7

In [10]: # 注意此处跳过了56,我们可以再移除一个元素

In [11]: l.remove(4)

In [12]: next(it)
Out[12]: 9
复制代码

Das obige Experiment zeigt, dass Sie, wenn Sie ein Element entfernen, das ein Iterator bereits besucht hat, bei der nächsten Iteration ein Element auf der rechten Seite überspringen und direkt zum nächsten gehen.

Das Gegenteil ist immer noch der Fall, das heißt, wenn Sie nach dem Start der Iteration ein Element am Anfang der Liste hinzufügen, kann die nächste Iteration auf das bereits iterierte Element zugreifen. Dies geschieht in folgendem Code:

In[1]: l = [3, 4, 56, 7, 10, 9, 6, 5]

In[2]: it = iter(l)

In[3]: next(it)
Out[3]: 3

In[4]: next(it)
Out[4]: 4

In[5]: l.insert(0, 44)

In[6]: next(it)
Out[6]: 4
复制代码

Beachten Sie, dass beim Hinzufügen von 44 zum Kopf der Liste zweimal auf 4 zugegriffen wird.

2. Lösungen

Um das obige Problem zu lösen, müssen wir sicherstellen, dass die vom Iterator besuchten Elemente nicht entfernt werden können.

Option eins

Wir können zuerst die ursprüngliche Liste umdrehen, um eine neue Liste zu erhalten, dann über die neue Liste iterieren und die Elemente entfernen, die die Bedingungen in der ursprünglichen Liste l nicht erfüllen. Der Programmcode lautet wie folgt:

l = [3, 4, 56, 7, 10, 9, 6, 5]

# 迭代翻转后的列表
for i in reversed(l):
    print(i)
    if not i % 2 == 0:
        continue
    l.remove(i)

print(l)
复制代码

Das Ergebnis ist wie folgt:

5
6
9
10
7
56
4
3
[3, 7, 9, 5]
复制代码

Beachten Sie, dass der Iterator jetzt erfolgreich auf alle Elemente in der Liste zugreift und schließlich eine Liste ausgibt, die nur ungerade Zahlen enthält.

Variante II

Wir können die Liste l auch kopieren, bevor wir mit der Iteration beginnen. Aber wenn zu viele Daten in der Liste l sind, ist dies offensichtlich performance-intensiver. Der Programmcode lautet wie folgt:

l = [3, 4, 56, 7, 10, 9, 6, 5]

# 在这里使用 'l.copy()' 来对列表 l 进行浅拷贝
for i in l.copy():  
    print(i)   
    if not i % 2 == 0:     
        continue  
    l.remove(i)
    
print(l)
复制代码

Die Ausgabe ist wie folgt:

3
4
56
7
10
9
6
5
[3, 7, 9, 5]
复制代码

Dieses Schema stellt sicher, dass die Reihenfolge der Iteration dieselbe ist wie die Reihenfolge, in der Elemente entfernt werden. Aber da sich die beiden Operationen iterate und remove auf zwei verschiedenen Listen befinden, spielt es keine Rolle, dass die Reihenfolge dieselbe ist.

2. Über das Wörterbuch

1. Problembeschreibung

Das Wörterbuch kann nicht geändert werden, während das Wörterbuch durchlaufen wird. wie folgt:

# {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
d = {k: k for k in range(10)}

for k, v in d.items():  
    if not v % 2 == 0:    
        continue  
    d.pop(k)
复制代码

Dieser Code erzeugt einen RuntimeError:

Traceback (most recent call last):  
  File "F:/Documents/pythonprojects/01practice/app.py", line 7, in <module>  
    for k, v in d.items():
RuntimeError: dictionary changed size during iteration
复制代码

2. Lösungen

Wir können zuerst alle Schlüssel des Wörterbuchs kopieren und dann beim Iterieren der Schlüssel die Elemente entfernen, die die Bedingungen nicht erfüllen. Der Ablauf ist wie folgt:

# {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
d = {k: k for k in range(10)}
# 这里复制了字典中的所有key值
# 没有复制整个字典
# 同时使用tuple()速度更快
for k in tuple(d.keys()):   
    if not d[k] % 2 == 0:    
        continue  
    d.pop(k)
    
print(d)
复制代码

Die Ausgabe nach dem Ausführen des Codes lautet wie folgt:


{1: 1, 3: 3, 5: 5, 7: 7, 9: 9}
复制代码

Wir haben erfolgreich alle geraden Schlüssel-Wert-Paare aus dem Wörterbuch entfernt!

abschließend

In diesem Artikel schlagen wir verschiedene Lösungen für das Problem vor, dass es beim Iterieren über einen Datensatz nicht geändert werden kann: Wenn wir die Liste beim Durchlaufen der Liste ändern möchten, können wir zuerst die ursprüngliche Liste umdrehen oder kopieren, um eine neue Liste zu erhalten , dann ändern Sie beim Durchlaufen der neuen Liste die Daten in der ursprünglichen Liste; wenn wir das Wörterbuch beim Durchlaufen des Wörterbuchs ändern möchten, können wir zuerst alle Schlüsselwerte des Wörterbuchs kopieren und dann beim Iterieren darüber die Schlüsselwerte , ändern Sie die Daten im Wörterbuch.

Vielen Dank

Aufgrund des Mangels an Talent und Wissen des Autors und der begrenzten Zeit und Energie sind Fehler im Code unvermeidlich, und die Leser können sie gerne kritisieren und korrigieren.

Haftungsausschluss: Dieser Artikel wird veröffentlicht, um mehr Wissen zum Austausch und Lernen weiterzugeben. Wenn die Quelle falsch gekennzeichnet ist oder Ihre gesetzlichen Rechte verletzt    , kontaktieren Sie uns bitte mit dem Eigentumsnachweis, und wir werden ihn rechtzeitig korrigieren oder löschen, danke.

Ich denke du magst

Origin juejin.im/post/7086266876438790151
Empfohlen
Rangfolge