Теперь я знаю, что изменять список во время итеративного цикла небезопасно. Однако предположим, что у меня есть список строк, и я хочу удалить сами строки. Считается ли замена изменяемых значений модификацией?
Теперь я знаю, что изменять список во время итеративного цикла небезопасно. Однако предположим, что у меня есть список строк, и я хочу удалить сами строки. Считается ли замена изменяемых значений модификацией?
Ответы:
Это считается плохой формой. Вместо этого используйте понимание списка с назначением срезов, если вам нужно сохранить существующие ссылки на список.
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 Tutorial даже не упоминает об этом. Хотя должна быть какая-то причина?
a[i]и s) для одного и того же объекта в одной строке, когда вам не нужно? Я бы предпочел сделать a[i] = a[i].strip().
a[i] = s.strip()только одна операция индексации.
enumerate(b)выполняет операцию индексации на каждой итерации, а вы выполняете еще одну a[i] =. AFAIK Невозможно реализовать этот цикл в Python, используя только одну операцию индексации на одну итерацию цикла :(
Еще один вариант цикла, мне кажется, чище, чем 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как это генератор, он не создает список кортежей, он создает их по одному за раз, просматривая список. Единственный способ определить, что медленнее, - это timeit.
Модификация каждого элемента во время итерации списка - это хорошо, если вы не изменяете добавление / удаление элементов в список.
Вы можете использовать понимание списка:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
или просто сделайте C-styleцикл for:
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)
который меняет my_strings на ['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"]]