Найти - Пользователи
Полная версия: изменение list/dict в цикле на лету - можно или нет?
Начало » Python для новичков » изменение list/dict в цикле на лету - можно или нет?
1 2
test157
всем привет

интересно вот что - можно ли удалять или модифицировать массив или словарь внутри цикла по самому этому массиву?

вот такой вариант - у меня ломал данные, когда arr был листом.
for idx, v in arr:
if something():
del(arr[idx]);
а вот будет ли корректно работать словарь? тамже нету упорядоченных данных в теории.
for k, v in slovar.iteritems():
if something():
del(slovar[k]);
такто вроде все работает - но блин, обычно это вылезает в виде сложно отлавливаемых багов - как это было с листом. такчто хотелось бы уточнить этот момент
Ferroman
Что такое “массив”?
В питоне есть только один массив - это ассоциативный массив aka “словарь”. Или это просто как синоним коллекции?
Ответ - нельзя.
iteritems - возвращает итератор с словаря, что не есть словарь, т.е. словарь может модифицироватся, на работу итератора в цикле, на прямую, не повлияет.
Для списка можно использовать такой приём (он есть, кстати, в официальном туториале):
 for idx, v in arr[:]:
а вот будет ли корректно работать словарь?
Не стоит на это полагаться.

ЗЫ: точки с запятыми в конце - паскалевское наследие ;) ?
bw
Чем не вариант для словаря?
>>> d = {1: 'a', 2: 'b', 3: 'c', 0: 'z'}
>>> for k, v in list(d.iteritems()):
... if v < 'c':
... del d[k]
...
>>> d
{0: 'z', 3: 'c'}
Если словарь большой, то это плохая идея, так как выполняется его копия (и приводится к списку).

Что такое arr, список из кортежей в элемента?
Почему не сделать так (никакого idx в списке, не понял зачем он)?

>>> l = ['a', 'b', 'c']
>>> for i, v in list(enumerate(l))[::-1]:
... if v < 'c':
... del [i]
...
>>> l
['c']
Список дополняется индексом (для каждого элемента) и выполняется обратный обход по его копии.
Если список большой, то это плохая идея, так как выполняется его копия с парой (индексом) для каждого элемента.

p.s. Это первое, что пришло в голову.

..bw
Ferroman
так как выполняется его копия (и приводится к списку).
Это не правда. iteritems не приводит словарь к списку.

test157
И, кстати, индекс таким способом не получишь. Разве что список уже содержит индексы.
test157
както я больше запутался - чем разобрался. пожалуй укажу типы данных в моем примере выше.

arr = [1, 2, 3, 'd', 'c']
for idx, v in enumerate(arr):
if something():
del(arr[idx])
1. вопрос номер один, я хочу таким образом, удалять не нужные мне элементы. ну это ведь часто бывает? в целом я это пробовал, и оно не работает - еле отловил. вариант от Ferroman я понял, и он действительно сработает - но это ведь копия для больших объемов вариант не супер. в общем еще раз суть вопроса, нужно внутри цикла интерации по массиву - иметь возможность удалять или добавлять новые элементы в этот массив. массив = LIST в моем понимании.

и вопрос номер два - все тоже самое только дело мы имеем со словарем:
slovar = {'s':'s', 'd':'f'}
for k, v in slovar.iteritems():
if something():
del(slovar[k]);
2. и вопрос номер два, как я понял - это тоже лучше не делать да? предварительно не создав копию словаря а потом уже бегать по копии а менять оригинал?

P.S.: точка с запятой наследие ПХП - приходится писать параллельно и на том и на том, отсюда часто остаются скобки и точки с запятой, но борюсь как могу )
bw
> Это не правда. iteritems не приводит словарь к списку.

Будь внимательнее – list(d.iteritems()). Ну я тут конечно загнул, достаточно использовать .items().

Вот я блин даю :-), так можно сделать:
>>> d = {1: 'a', 2: 'b', 3: 'c', 0: 'z'}
>>> dict(filter(lambda (k, v): 'c' <= v, d.iteritems()))
{0: 'z', 3: 'c'}
Для списка:
>>> l = ['a', 'b', 'c']
>>> filter(lambda v: 'c' <= v, l)
['c']
Что такое lambda и filter найдешь в справочнике.
В первом случае k и v обязательно должны быть в скобках. Лямбде передается один аргумент, это кортеж из ключа и значения, как понимаешь, этот кортеж является элементом списка/итератора возвращаемого методом .items()/.iteritems() словаря. Или лямбда могла быть такой: lambda item: ‘c’ <= item. Что менее выразительно.

p.s. Всё гениальное просто :-).

..bw
bw
Или есть такой вариант:
>>> l = ['a', 'b', 'c']
>>> [v for v in l if 'c' <= v]
['c']
..bw
test157
нет это все понятно - но вопрос не в этом. вопрос в том можно ли в ЦИКЛЕ изменять (удалять добавлять новые элементы) СЛОВАРЬ или ЛИСТ по которому ты бегаешь. предложенные варианты, это все ясно - но они не подходят когда цикл должен содержать более сложную логику, на основе которой принимается решение - по удалению или удалению новых элементов в СЛОВАРЬ или ЛИСТ по которому бегаешь.
bw
> можно ли в ЦИКЛЕ изменять (удалять добавлять новые элементы) СЛОВАРЬ или ЛИСТ по которому ты бегаешь
Можно, как показано выше, в примере с созданием копии словаря/списка.

> подходят когда цикл должен содержать более сложную логику
Вынеси логику в функцию и передай эту функцию filter. Не вижу здесь проблем.
>>> def something(value):
... if value < 'c':
... return False
... return True
...
>>> l = ['a', 'b', 'c', 'z']
>>> l = filter(something, l)
>>> l
['c', 'z']
Конечно, это не удаление из списка, а формирование нового, но такой вариант, сейчас, мне видится более оптимальным, чем создание копий.

..bw
Striver
Если мне в цикле нужно модифицировать список, я пробегаю не по нему , а по его номерам. Если ещё и удалять понадобится, то иду в обратную сторону. Хоть и выглядит не так красиво, зато заморачиваться не приходится
for num in xrange(len(spisok)-1:-1:-1):
if something():
del(spisok[num]);
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB