2013-04-19 2 views
5

Каков правильный способ выполнения нескольких итераций по контейнеру? Из питона документации:Правильный способ повторения дважды по списку?

Итератор - Объект-контейнер (например, список) производит свежий новый итератор каждый раз, когда вы передаете его функции ИТЭР() или использовать его в цикл. Попытка этого с помощью итератора будет возвращать тот же самый искушенный объект итератора , используемый в предыдущем проходе итерации, делая , он выглядит как пустой контейнер.

Целью протокола является то, что после того, как метод next() итератора вызывает StopIteration, он будет продолжать делать это при последующих вызовах. Реализации, которые не подчиняются этому имуществу, считаются нарушенными. (Это ограничение было добавлено в Python 2.3, в Python 2.2, различные итераторы разбиты в соответствии с этим правилом.)

Если у меня есть этот код:

slist = [1,2,3,4] 
rlist = reversed(slist) 
list(rlist) 
#[4,3,2,1] 
tuple(rlist) 
#() 

Что бы самым простым и самый правильный способ повторить повторение «rlist» дважды?

+4

Обратите внимание, что вы не итерацию над списком дважды - это легко. Вы на самом деле повторяете « 'дважды. – mgilson

ответ

7
rlist = list(reversed(slist)) 

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

def tosequence(it): 
    """Turn iterable into a sequence, avoiding a copy if possible.""" 
    if not isinstance(it, collections.Sequence): 
     it = list(it) 
    return it 

(Sequence является абстрактным типом списков, кортежей и многих пользовательских списков, как объекты.)

+0

Зачем беспокоиться о тестировании? Я ожидал, что нет никакой стоимости для 'it = list (it)', если 'it' уже является списком. Разве это не так? –

5

I Wouldn «т хранится список дважды, если вы не можете комбинировать его итерацию один раз, то я бы

slist = [1,2,3,4] 
for element in reversed(slist): 
    print element # do first iteration stuff 
for element in reversed(slist): 
    print element # do second iteration stuff 

Просто думать о негативах() как создание реверсивного итератора на SLIST. Обратный дешевый. При этом, если вы только когда-либо нуждаетесь в его обратном, я бы отменил его и просто сохранил так.

+1

+1 - Вызов 'reverse (slist)' создает только новый объект итератора, который намного дешевле, чем 'list (reverse (slist))', который создает копию всего списка. – Aya

3

Каков правильный способ выполнения нескольких итераций по контейнеру?

Просто делайте это дважды подряд. Нет проблем.

Что было бы самым простым и правильным способом перебора по «rlist» дважды?

Престол, причина того, что не работает для вас, что rlistне «контейнер».

Обратите внимание, как

list(slist) # another copy of the list 
tuple(slist) # still works! 

Таким образом, простое решение, чтобы просто обеспечить вам реальную емкость элементов, если вам нужно перебирать несколько раз:

rlist = list(reversed(slist)) # we store the result of the first iteration 
# and then that result can be iterated over multiple times. 

Если вы действительно не должны хранить пункты, попробуйте itertools.tee. Но имейте в виду, что вам не удастся избежать хранения элементов, если вам нужно выполнить одну полную итерацию перед началом следующего. В общем случае хранилище действительно неизбежно при этих ограничениях.

1

Почему бы вам просто не перевернуть исходный список на месте (slist.reverse()), а затем перебрать его столько раз, сколько пожелаете, и, наконец, снова отменить его снова, чтобы получить исходный список еще раз?

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

for _ in xrange(as_many_times_as_i_wish_to_iterate_this_list_in_reverse_order): 
    for x in reversed(slist): 
     do_stuff(x) 
+0

//, Почему вы используете '_' в качестве имени переменной здесь? Это какая-то конвенция? –

+0

I (и я видел, как другие люди это делают) присваивают значения выкидыша переменной подчеркивания. Таким образом, когда я прочитаю код, я сразу же узнаю, что это значение не имеет значения. С другой стороны, библиотека 'gettext' использует функцию' _() '... поэтому я предполагаю, что в некоторых контекстах это плохое имя для переменной throw-away. –

Смежные вопросы