Как изменить записи списка во время цикла for? - PullRequest
129 голосов
/ 02 ноября 2010

Теперь я знаю, что изменять список во время итеративного цикла небезопасно. Однако предположим, что у меня есть список строк, и я хочу удалить сами строки. Считается ли замена изменяемых значений модификацией?

Ответы [ 8 ]

129 голосов
/ 03 ноября 2010

Поскольку указанный ниже цикл изменяет только элементы, которые уже видны, это будет считаться приемлемым:

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
108 голосов
/ 02 ноября 2010

Это считается плохой формой. Вместо этого используйте понимание списка с назначением срезов, если вам нужно сохранить существующие ссылки на список.

a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
17 голосов
/ 24 сентября 2013

Еще один вариант цикла, мне кажется, чище, чем 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
9 голосов
/ 03 мая 2017

Изменение каждого элемента во время итерации списка - это хорошо, если вы не изменяете добавление / удаление элементов в список.

Вы можете использовать понимание списка:

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()
3 голосов
/ 07 июля 2017

Вы можете сделать что-то вроде этого:

a = [1,2,3,4,5]
b = [i**2 for i in a]

Это называется пониманием списка, чтобы упростить цикл внутри списка.

3 голосов
/ 02 ноября 2010

Нет, вы не изменили бы «содержимое» списка, если бы могли изменять строки таким образом.Но в Python они не изменчивы.Любая строковая операция возвращает новую строку.

Если у вас был список объектов, которые, как вы знали, были изменяемыми, вы могли бы делать это, если вы не изменили фактическое содержимое списка.* Таким образом, вам нужно будет сделать карту какого-то рода.Если вы используете выражение генератора, оно [операция] будет выполнено во время итерации, и вы сэкономите память.

1 голос
/ 11 апреля 2019

Ответ, данный Джемшитом Искендеровым и Игнасио Васкес-Абрамсом, действительно хорош. Это может быть дополнительно проиллюстрировано на следующем примере: представьте, что

a) Вам дан список с двумя векторами;

b) вы хотите просмотреть список и изменить порядок каждого из массивов

Допустим, у вас есть

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([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])]
1 голос
/ 11 сентября 2014

Из вашего вопроса непонятно, каковы критерии принятия решения о том, какие строки удалить, но если у вас есть или можно составить список строк, которые вы хотите удалить, вы можете сделать следующее:

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']

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...