2012-03-10 3 views
1

Я пытаюсь написать класс, который работает так же, как цикл из модуля itertools, но имеет некоторые дополнительные функции. Я хочу иметь возможность удалять элементы из списка, по которому я выполняю итерацию.цикл с возможностью удаления элементов

Вот мой код:

class myCycle(object): 
    def __init__(self, list): 
     self.list = list 

    def __iter__(self): 
     def iter(self): 
      while True: 
       if not self.list: 
        break 
       for e in self.list: 
        yield e 
     return iter(self) 

    def remove(self, e): 
     self.list.remove(e) 

Он отлично работает с одним исключением. Давайте посмотрим на пример:

>>> for i in c: 
...  print i 
...  if i == 1: 
...   c.remove(1) 
...  if i == 3: 
...   break 
... 
1 
3 
>>> 

После удаления 1 из списка, индекс двигаться и что, вероятно, причина, почему я не имею 2 в моем выходе.

Но как я могу заставить его работать? Или, может быть, есть другой способ получить эту функциональность?

EDIT:

После ваших комментариев я попытаюсь объяснить, что я пытаюсь сделать.

У меня есть строка с действиями игрока, который может выглядеть как этот:

actions = "sBcffcffcfrfccc" 

Это от покера, действие е означают раз, с вызовом и так один. Самое интересное для нас - фолд.

И у меня есть список игроков:

players = ['Saxum', 'Erasmus', 'Anders', 'Ginger', 'Adam', 
      'Crusoe', 'OgoPogo', 'Hari', 'Sanja', 'Hooke'] 

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

Saxum -> s 
Erasmus -> B 
Anders -> c 
Ginger -> f 

Ginger folded, we should remove this player. So how player list look like now: 

    players = ['Saxum', 'Erasmus', 'Anders', 'Adam', 
       'Crusoe', 'OgoPogo', 'Hari', 'Sanja', 'Hooke'] 

Adam -> f 

Adam folded, we should remove this player. So how player list look like now: 

    players = ['Saxum', 'Erasmus', 'Anders', 
       'Crusoe', 'OgoPogo', 'Hari', 'Sanja', 'Hooke'] 

Crusoe -> c 
OgoPogo -> f 

OgoPogo folded, we should remove this player. So how player list look like now: 

    players = ['Saxum', 'Erasmus', 'Anders', 
       'Crusoe', 'Hari', 'Sanja', 'Hooke'] 

Hari -> f 

Hari folded, we should remove this player. So how player list look like now: 

    players = ['Saxum', 'Erasmus', 'Anders', 
       'Crusoe', 'Sanja', 'Hooke'] 

Sanja -> c 
Hooke -> f 

Hooke folded, we should remove this player. So how player list look like now: 

    players = ['Saxum', 'Erasmus', 'Anders', 
       'Crusoe', 'Sanja'] 

Hooke was last on the list, so we start from beginning. 

Saxum -> r 
Erasmus -> f 

Erasmus folded, we should remove this player. So how player list look like now: 

    players = ['Saxum', 'Anders', 
      'Crusoe', 'Sanja'] 

Anders -> c 
Crusoe -> c 
Sanja -> c 

И вот почему я начал реализовывать myCycle. Но, может быть, есть лучший способ сделать это?

+0

Нужно ли удалять элементы во время цикла, или это может быть пакетное удаление их по завершении? – heltonbiker

+0

Мне нужно удалить элементы во время цикла ... – Adam

+3

Не делайте этого. Изменение итерации при итерации - ужасная идея. Я уверен, что вы можете придумать более приятное решение. –

ответ

3

Не удаляйте элементы, которые ушли из списка - заменить их None вместо:

class MyCycle(object): 
    def __init__(self, lst): 
     self.list = lst 

    def __iter__(self): 
     while True: 
      items_left = False 
      for x in self.list: 
       if x is not None: 
        items_left = True 
        yield x 
      if not items_left: 
       return 

    def remove(self, e): 
     self.list[self.list.index(e)] = None 
+0

Спасибо, эта идея отлично подходит для меня. – Adam

2

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

index = 0 

while index < len(my_list): 
    if got_to_remove(my_list[index]): 
     del l[index] 
    else: 
     index += 1 

Теперь, как это было указано в комментариях к вашему вопросу, вы, вероятно, найти более элегантное решение проблемы.

1

На самом деле, это выполнимо вручную крафт итератора, а не с помощью функции генератора.

class myCycle(object): 
    def __init__(self, list): 
     self.list = list 
     self.i = 0 

    def __next__(self): 
     try: 
      return self.list[self.i] 
     except IndexError: 
      raise StopIteration, "list is empty" 
     finally: 
      self.i = self.i + 1 
      if self.i >= len(self.list): 
       self.i = 0 
    next = __next__ 

    def __iter__(self): 
     return self 

    def remove(self, e): 
     i = self.list.index(e) 
     del self.list[i] 
     if self.i >= i: 
      self.i = self.i - 1 
     if self.i >= len(self.list): 
      self.i = 0 
Смежные вопросы