Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 18, 2009 06:33:00

test157
От:
Зарегистрирован: 2009-02-25
Сообщения: 54
Репутация: +  0  -
Профиль   Отправить e-mail  

изменение list/dict в цикле на лету - можно или нет?

всем привет

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

вот такой вариант - у меня ломал данные, когда arr был листом.

for idx, v in arr:
if something():
del(arr[idx]);
а вот будет ли корректно работать словарь? тамже нету упорядоченных данных в теории.
for k, v in slovar.iteritems():
if something():
del(slovar[k]);
такто вроде все работает - но блин, обычно это вылезает в виде сложно отлавливаемых багов - как это было с листом. такчто хотелось бы уточнить этот момент



Офлайн

#2 Авг. 18, 2009 16:40:20

Ferroman
От:
Зарегистрирован: 2006-11-16
Сообщения: 2759
Репутация: +  1  -
Профиль   Отправить e-mail  

изменение list/dict в цикле на лету - можно или нет?

Что такое “массив”?
В питоне есть только один массив - это ассоциативный массив aka “словарь”. Или это просто как синоним коллекции?
Ответ - нельзя.
iteritems - возвращает итератор с словаря, что не есть словарь, т.е. словарь может модифицироватся, на работу итератора в цикле, на прямую, не повлияет.
Для списка можно использовать такой приём (он есть, кстати, в официальном туториале):

 for idx, v in arr[:]:
а вот будет ли корректно работать словарь?
Не стоит на это полагаться.

ЗЫ: точки с запятыми в конце - паскалевское наследие ;) ?

Отредактировано (Авг. 18, 2009 16:41:29)

Офлайн

#3 Авг. 18, 2009 17:48:09

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

изменение list/dict в цикле на лету - можно или нет?

Чем не вариант для словаря?

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



Отредактировано (Авг. 18, 2009 17:52:55)

Офлайн

#4 Авг. 18, 2009 18:16:54

Ferroman
От:
Зарегистрирован: 2006-11-16
Сообщения: 2759
Репутация: +  1  -
Профиль   Отправить e-mail  

изменение list/dict в цикле на лету - можно или нет?

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

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

Отредактировано (Авг. 18, 2009 18:18:31)

Офлайн

#5 Авг. 18, 2009 18:47:45

test157
От:
Зарегистрирован: 2009-02-25
Сообщения: 54
Репутация: +  0  -
Профиль   Отправить e-mail  

изменение list/dict в цикле на лету - можно или нет?

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

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.: точка с запятой наследие ПХП - приходится писать параллельно и на том и на том, отсюда часто остаются скобки и точки с запятой, но борюсь как могу )



Отредактировано (Авг. 18, 2009 18:49:05)

Офлайн

#6 Авг. 18, 2009 19:03:07

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

изменение list/dict в цикле на лету - можно или нет?

> Это не правда. 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



Отредактировано (Авг. 18, 2009 19:07:32)

Офлайн

#7 Авг. 18, 2009 19:27:44

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

изменение list/dict в цикле на лету - можно или нет?

Или есть такой вариант:

>>> l = ['a', 'b', 'c']
>>> [v for v in l if 'c' <= v]
['c']
..bw



Офлайн

#8 Авг. 19, 2009 09:02:24

test157
От:
Зарегистрирован: 2009-02-25
Сообщения: 54
Репутация: +  0  -
Профиль   Отправить e-mail  

изменение list/dict в цикле на лету - можно или нет?

нет это все понятно - но вопрос не в этом. вопрос в том можно ли в ЦИКЛЕ изменять (удалять добавлять новые элементы) СЛОВАРЬ или ЛИСТ по которому ты бегаешь. предложенные варианты, это все ясно - но они не подходят когда цикл должен содержать более сложную логику, на основе которой принимается решение - по удалению или удалению новых элементов в СЛОВАРЬ или ЛИСТ по которому бегаешь.



Офлайн

#9 Авг. 19, 2009 12:07:25

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

изменение list/dict в цикле на лету - можно или нет?

> можно ли в ЦИКЛЕ изменять (удалять добавлять новые элементы) СЛОВАРЬ или ЛИСТ по которому ты бегаешь
Можно, как показано выше, в примере с созданием копии словаря/списка.

> подходят когда цикл должен содержать более сложную логику
Вынеси логику в функцию и передай эту функцию filter. Не вижу здесь проблем.

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

..bw



Отредактировано (Авг. 19, 2009 12:16:10)

Офлайн

#10 Авг. 19, 2009 12:10:44

Striver
От:
Зарегистрирован: 2006-10-26
Сообщения: 247
Репутация: +  22  -
Профиль   Отправить e-mail  

изменение list/dict в цикле на лету - можно или нет?

Если мне в цикле нужно модифицировать список, я пробегаю не по нему , а по его номерам. Если ещё и удалять понадобится, то иду в обратную сторону. Хоть и выглядит не так красиво, зато заморачиваться не приходится

for num in xrange(len(spisok)-1:-1:-1):
if something():
del(spisok[num]);



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version