2016-12-02 2 views
3

Редактировать: Существует similar question here, который имеет дело с сбросом итератора. В принятом ниже ответе решается актуальная проблема вложенных итераторов и обрабатывается легко пропустить проблему, при которой вложенный итератор не сбрасывается.Python - Итерация итератора дважды

Есть ли способ перебрать итератор дважды в python?

В приведенном ниже примере кода я вижу, что вторая итерация работает на том же объекте, что и первая, и, таким образом, дает странный результат. Сравните это с C# ниже, что дает результат, который я получил после.

Есть ли способ делать то, что я хочу. Мне было интересно, могу ли я сделать копию итератора или «восстановить» функцию, из которой он пришел, но, возможно, есть более простой способ. (Я знаю, что я мог бы просто позвонить MyIter() дважды в примере с игрушкой ниже, но это бесполезно, если я не знаю, откуда итератор пришел, и не то, что мне нужно!).

def MyIter(): 
    yield 1; 
    yield 2; 
    yield 3; 
    yield 4; 

def PrintCombos(x): 
    for a in x: 
     for b in x: 
      print(a,"-",b); 

PrintCombos(MyIter()); 

дает

1 - 2 
1 - 3 
1 - 4 

Контраст с:

static IEnumerable MyIter() 
{ 
    yield return 1; 
    yield return 2; 
    yield return 3; 
    yield return 4; 
} 

static void PrintCombos(IEnumerable x) 
{ 
    foreach (var a in x) 
     foreach (var b in x) 
      Console.WriteLine(a + "-" + b); 
} 

public static void Main(String[] args) 
{ 
    PrintCombos(MyIter()); 
} 

Что дает:

1-1 
1-2 
1-3 
1-4 
2-1 
2-2 
. . . 
+2

Вы можете перебирать итераторы неограниченное количество раз в python. Однако, если вы ссылаетесь на генераторы (которые вы видите по внешнему виду кода), нет никакого способа сделать это несколько раз на самом генераторе. Однако вы можете сохранить результаты генератора в памяти и перебрать их. В приведенном вами примере вы сделаете это, вызвав 'PrintCombos (список (MyIter())) –

+0

[' itertools.tee'] (https://docs.python.org/3/library/itertools.html # itertools.tee) может быть то, что вы ищете. – Matthias

+0

Возможный дубликат [Итераторы могут быть сброшены в Python?] (Http://stackoverflow.com/questions/3266180/can-iterators-be-reset-in-python) –

ответ

1

Вы можете использовать itertools.tee для создания нескольких копий генератора

from itertools import tee 

def MyIter(): 
    yield 1 
    yield 2 
    yield 3 
    yield 4 

def PrintCombos(x): 
    it1, it2 = tee(x, 2) 
    for a in it1: 
     it2, it3 = tee(it2, 2) 
     for b in it3: 
     print("{0}-{1}".format(a, b)) 

PrintCombos(MyIter()) 
-1

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

x = [1,2,3,4] 
y = [1,2,3,4] 

spam = [[s,t] for s in x for t in y] 

for x in spam: 
    print('%s - %s' %(x[0], x[1])) 

выход:

1 - 1 
1 - 2 
1 - 3 
1 - 4 
2 - 1 
2 - 2 
2 - 3 
2 - 4 
3 - 1 
3 - 2 
3 - 3 
3 - 4 
4 - 1 
4 - 2 
4 - 3 
4 - 4 
1

itertools.tee создает независимые итераторы из одного Iterable. Однако, как только будут созданы новые итерации, исходный итерируемый больше не должен использоваться.

import itertools 
def MyIter(): 
    yield 1; 
    yield 2; 
    yield 3; 
    yield 4; 

def PrintCombos(x): 
    xx = [] 
    xx.append(itertools.tee(x)) 
    n = 0 
    for a in xx[0][0]: 
     xx.append(itertools.tee(xx[n][1])) 
     for b in xx[n+1][0]: 
      print('%s - %s' % (a,b)); 
     n += 1 

PrintCombos(MyIter()); 
Смежные вопросы