Teraz wiem, że modyfikowanie listy podczas iteracyjnego zapętlenia nie jest bezpieczne. Załóżmy jednak, że mam listę strun i chcę je usunąć. Czy zastąpienie wartości zmiennych liczy się jako modyfikacja?
Teraz wiem, że modyfikowanie listy podczas iteracyjnego zapętlenia nie jest bezpieczne. Załóżmy jednak, że mam listę strun i chcę je usunąć. Czy zastąpienie wartości zmiennych liczy się jako modyfikacja?
Odpowiedzi:
Uważa się, że jest to kiepska forma. Zamiast tego użyj funkcji list składanych, z przypisaniem wycinka, jeśli chcesz zachować istniejące odniesienia do listy.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
print binstrukcja jest wykonywana, możesz stwierdzić, czy azostała zmodyfikowana w miejscu, a nie zastąpiona. Inną możliwością byłoby print b is asprawdzenie, czy oba nadal odnoszą się do tego samego obiektu.
Ponieważ pętla poniżej modyfikuje tylko elementy już widoczne, byłoby to akceptowalne:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Co różni się od:
a[:] = [s.strip() for s in a]
ponieważ nie wymaga tworzenia tymczasowej listy i przypisywania jej w celu zastąpienia oryginału, chociaż wymaga więcej operacji indeksowania.
Uwaga: chociaż możesz modyfikować wpisy w ten sposób, nie możesz zmienić liczby pozycji w listbez ryzyka wystąpienia problemów.
Oto przykład tego, co mam na myśli - usunięcie wpisu zakłóca indeksowanie od tego momentu:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(Wynik jest nieprawidłowy, ponieważ nie usunął wszystkich elementów, które powinien mieć).
Aktualizacja
Ponieważ jest to dość popularna odpowiedź, oto jak skutecznie usuwać wpisy „w miejscu” (nawet jeśli nie o to dokładnie chodzi):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
for i in a? Jest to bardzo sprzeczne z intuicją, pozornie różni się od innych języków i spowodowało błędy w moim kodzie, które musiałem debugować przez długi czas. Samouczek Pythona nawet o tym nie wspomina. Chociaż musi być jakiś powód?
a[i]i s) dla tego samego obiektu w tej samej linii, skoro nie musisz? Wolałbym to zrobić a[i] = a[i].strip().
a[i] = s.strip()wykonuje tylko jedną operację indeksowania.
enumerate(b)wykonuje operację indeksowania w każdej iteracji, a ty robisz kolejną z a[i] =. AFAIK niemożliwe jest zaimplementowanie tej pętli w Pythonie z tylko 1 operacją indeksowania na iterację pętli :(
Jeszcze jeden wariant pętli wygląda dla mnie czystszy niż wariant z enumerate ():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension
range(len(list))w Pythonie pachnie kodem.
enumeratejest generatorem, nie tworzy listy krotek, tworzy je pojedynczo podczas iteracji po liście. Jedynym sposobem, aby stwierdzić, który jest wolniejszy, jest timeit.
Modyfikowanie każdego elementu podczas iteracji listy jest w porządku, o ile nie zmieniasz opcji dodawania / usuwania elementów do listy.
Możesz użyć rozumienia list:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
lub po prostu wykonaj C-stylepętlę for:
for index, item in enumerate(l):
l[index] = item.strip()
Nie, nie zmieniłbyś „zawartości” listy, gdybyś mógł w ten sposób zmienić ciągi znaków. Ale w Pythonie nie można ich zmieniać. Każda operacja na łańcuchach zwraca nowy ciąg.
Gdybyś miał listę obiektów, o których wiedziałeś, że są zmienne, możesz to zrobić, o ile nie zmieniasz rzeczywistej zawartości listy.
Dlatego będziesz musiał zrobić jakąś mapę. Jeśli użyjesz wyrażenia generatora, to [operacja] zostanie wykonana podczas iteracji i zaoszczędzisz pamięć.
Odpowiedź udzielona przez Jemshit Iskenderov i Ignacio Vazquez-Abrams jest naprawdę dobra. Można to dalej zilustrować następującym przykładem: wyobraź sobie to
a) Otrzymujesz listę z dwoma wektorami;
b) chciałbyś przejść przez listę i odwrócić kolejność każdej z tablic
Powiedzmy, że masz
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # this command does not reverse the string
print([v,b])
Dostaniesz
[array([1, 2, 3, 4]), array([3, 4, 6])]
Z drugiej strony, jeśli to zrobisz
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # this command reverses the string
print([v,b])
Wynik to
[array([4, 3, 2, 1]), array([6, 4, 3])]
Z twojego pytania nie wynika jasno, jakie są kryteria decydujące o tym, jakie ciągi mają zostać usunięte, ale jeśli masz lub możesz utworzyć listę ciągów, które chcesz usunąć, możesz wykonać następujące czynności:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
co zmienia my_strings na ['a', 'c', 'e']
W skrócie, aby dokonać modyfikacji na liście podczas iteracji tej samej listy.
list[:] = ["Modify the list" for each_element in list "Condition Check"]
przykład:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]