Тепер я знаю, що це не безпечно змінювати список під час ітеративного циклу. Однак, припустимо, у мене є список рядків, і я хочу зняти самі рядки. Чи вважається заміна змінних значень модифікацією?
Тепер я знаю, що це не безпечно змінювати список під час ітеративного циклу. Однак, припустимо, у мене є список рядків, і я хочу зняти самі рядки. Чи вважається заміна змінних значень модифікацією?
Відповіді:
Це вважається поганою формою. Використовуйте розуміння списку замість цього, з призначенням фрагментів, якщо вам потрібно зберегти існуючі посилання на список.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
print bоператор виконується, ви можете сказати, чи aбуло змінено на місці, а не замінено. Іншою можливістю було б print b is aпобачити, чи обоє вони все ще посилаються на один і той же об'єкт.
Оскільки цикл внизу лише змінює елементи, які вже були помічені, це вважатиметься прийнятним:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Що відрізняється від:
a[:] = [s.strip() for s in a]
тим, що він не вимагає створення тимчасового списку та призначення його на заміну оригіналу, хоча це вимагає більше операцій з індексації.
Застереження: Хоча ви можете змінювати записи таким чином, ви не можете змінити кількість елементів у, listне ризикуючи виникнути проблеми.
Ось приклад того, що я маю на увазі - видалення запису з помилками індексації з цього моменту:
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!
(Результат невірний, оскільки він не видалив усі елементи, які він мав.)
Оновлення
Оскільки це досить популярна відповідь, ось як ефективно видалити записи "на місці" (хоча це не зовсім питання):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
for i in a? Це дуже контрінтуїтивно, начебто відрізняється від інших мов і призвело до помилок у моєму коді, які мені довелося налагоджувати протягом тривалого періоду часу. Підручник з Python навіть не згадує про це. Хоча для цього повинні бути якісь причини?
a[i]і s) для одного і того ж об'єкта в одному рядку, коли не потрібно? Я б набагато краще зробив a[i] = a[i].strip().
a[i] = s.strip()лише одна операція індексації.
enumerate(b)робить операцію індексації для кожної ітерації, а ви робите ще одну a[i] =. AFAIK неможливо реалізувати цю петлю в Python лише з 1 операцією індексації за цикл ітерації :(
Ще один варіант для циклу, виглядає для мене більш чистим, ніж один із 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))в Python кодовим запахом.
enumerateце генератор, він не створює list.of кортежів, він створює їх по одному, як він повторює список. Єдиним способом визначити, що повільніше, було б timeit.
Змінення кожного елемента під час ітерації списку є нормальним, доки ви не зміните додавання / видалення елементів до списку.
Ви можете використовувати розуміння списку:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
або просто зробіть C-styleцикл для:
for index, item in enumerate(l):
l[index] = item.strip()
Ні, ви б не змінювали "вміст" списку, якби ви могли таким чином змінити рядки. Але в Python вони не змінюються. Будь-яка операція рядка повертає новий рядок.
Якщо у вас був список об'єктів, які ви знали, що вони можуть змінюватися, ви можете це робити до тих пір, поки не зміните фактичний вміст списку.
Таким чином, вам потрібно буде зробити якусь карту. Якщо ви використовуєте генераторний вираз, це [операція] буде виконано під час ітерації, і ви збережете пам'ять.
Відповідь, яку дали Джемшит Іскендеров та Ігнасіо Васкес-Абрамс, справді хороша. Це можна додатково проілюструвати на цьому прикладі: уявіть це
а) Вам подано список з двома векторами;
б) ви хочете перейти список і змінити порядок кожного з масивів
Скажімо, у вас є
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])
Ти отримаєш
[array([1, 2, 3, 4]), array([3, 4, 6])]
З іншого боку, якщо це зробити
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])
Результат -
[array([4, 3, 2, 1]), array([6, 4, 3])]
З вашого запитання незрозуміло, які критерії для вирішення того, які рядки потрібно видалити, але якщо у вас є або можете скласти список рядків, які ви хочете видалити, ви можете зробити наступне:
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)
який міняє мої строки на ['a', 'c', 'e']
Коротше кажучи, зробити зміни в списку під час повторення того ж списку.
list[:] = ["Modify the list" for each_element in list "Condition Check"]
приклад:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]