python arbitralnie zwiększa iterator wewnątrz pętli

Prawdopodobnie robię to w niewłaściwy sposób, ale zastanawiałem się, jak sobie z tym poradzić w Pythonie.

Najpierw jakiś kod c:

int i;

for(i=0;i<100;i++){
  if(i == 50)
    i = i + 10;
  printf("%i\n", i);
}
Ok, więc nigdy nie widzimy lat 50-tych...

Moje pytanie brzmi, jak Mogę zrobić coś podobnego w Pythonie? Na przykład:

for line in cdata.split('\n'):
  if exp.match(line):
    #increment the position of the iterator by 5?
    pass
  print line

Z moim ograniczonym doświadczeniem w Pythonie, mam tylko jedno rozwiązanie, wprowadzam licznik i inne polecenie if. przerwij pętlę, aż licznik osiągnie 5 po exp.match (line) jest prawdą.

Istnieje musi to być lepszy sposób, mam nadzieję, że taki, który nie wymaga importowania innego modułu.

Z góry dzięki!
Author: jr0d, 2009-09-25

8 answers

Istnieje fantastyczny pakiet w Pythonie o nazwie itertools.

Ale zanim przejdę do tego, dobrze byłoby wyjaśnić, w jaki sposób protokół iteracji jest zaimplementowany w Pythonie. Jeśli chcesz podać iterację nad kontenerem, określ __iter__() metoda klasy zapewniająca Typ iteratora . "Understanding Python' s ' for 'statement" jest ciekawym artykułem opisującym, w jaki sposób deklaracja for-in faktycznie działa w Pythonie i dostarcza miłej informacji na temat tego, jak typy iteratora działają.

Spójrz na następujące:

>>> sequence = [1, 2, 3, 4, 5]
>>> iterator = sequence.__iter__()
>>> iterator.next()
1
>>> iterator.next()
2
>>> for number in iterator:
    print number 
3
4
5

A teraz wróć do itertools. Pakiet zawiera funkcje do różnych celów iteracyjnych. Jeśli kiedykolwiek potrzebujesz zrobić specjalne sekwencjonowanie, to jest pierwsze miejsce, aby przyjrzeć się.

Na dole znajdziesz sekcjęreceptury , która zawiera receptury tworzenia rozszerzonego zestawu narzędzi przy użyciu istniejących itertools jako bloków konstrukcyjnych .

I jest ciekawa funkcja, która dokładnie to, czego potrzebujesz:

def consume(iterator, n):
    '''Advance the iterator n-steps ahead. If n is none, consume entirely.'''
    collections.deque(itertools.islice(iterator, n), maxlen=0)

Oto szybki, czytelny przykład, jak to działa (Python 2.5):

>>> import itertools, collections
>>> def consume(iterator, n):
    collections.deque(itertools.islice(iterator, n))
>>> iterator = range(1, 16).__iter__()
>>> for number in iterator:
    if (number == 5):
        # Disregard 6, 7, 8, 9 (5 doesn't get printed just as well)
        consume(iterator, 4)
    else:
        print number

1
2
3
4
10
11
12
13
14
15
 43
Author: Filip Dupanović,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-29 17:18:47

Itertools.islice :

lines = iter(cdata.splitlines())
for line in lines:
    if exp.match(line):
       #increment the position of the iterator by 5
       for _ in itertools.islice(lines, 4):
           pass
       continue # skip 1+4 lines
    print line

Na przykład, jeśli exp, cdata są:

exp = re.compile(r"skip5")
cdata = """
before skip
skip5
1 never see it
2 ditto
3 ..
4 ..
5 after skip
6 
"""

Wtedy wyjście to:


before skip
5 after skip
6 

Implementacja języka C w Pythonie

i = 0
while i < 100:
    if i == 50:
       i += 10
    print i
    i += 1

Jak zauważył @ [Glenn Maynard] w w komentarzu Jeśli musisz wykonać bardzo duże skoki, takie jak i += 1000000000, powinieneś użyć jawnej pętli while zamiast po prostu pomijać kroki w pętli for.

Oto przykład, który używa jawnej pętli while zamiast islice:

lines = cdata.splitlines()
i = 0
while i < len(lines):
    if exp.match(lines[i]):
       #increment the position of the iterator by 5
       i += 5
    else:
       print lines[i]
       i += 1

Ten przykład daje taki sam wynik jak powyższy przykład islice.

 16
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:31

Jeśli robisz to z liczbami, zrozumienie listy może działać:

for i in [x for x in range(0, 99) if x < 50 and x > 59]:
    print i

Przesunięcie iteratora do przodu jest jednak nieco trudniejsze. Sugerowałbym wcześniejsze ustawienie listy, jeśli nie chcesz robić podejścia licznika, prawdopodobnie przez dzielenie cdata, a następnie wypracowanie indeksów pasującej linii i usunięcie tej linii i następujących. Poza tym utknąłeś z podejściem do licznika, które nie jest tak nieprzyjemne, jak robisz to, aby być szczerze.

Inna opcja jest taka:

iterator = iter(cdata.split('\n'))
for line in iterator:
    if exp.match(line):
        for i in range(0, 5):
            try:
                iterator.next()
            except StopIteration:
                break
    else:
        print line
 2
Author: Benno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-24 23:31:35

Nie jestem pewien, czy śledzę twój proces myślowy, ale tutaj jest coś, na czym można się pożywić..

for i in range(len(cdata.split('\n'))):
  if i in range(50,60): continue
  line = cdata[i]
  if exp.match(line):
    #increment the position of the iterator by 5?
    pass
  print line

Nie wiem, czego tak naprawdę szukasz, ale zakres (len (..)) powinno ci pomóc.

 1
Author: rh0dium,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-24 23:22:06

Możesz upuścić wartości z iteratora

def dropvalues(iterator, vals):
    for i in xrange(vals): iterator.next()

Upewnij się, że masz obiekt iterator do pracy z lines = iter(cdata.split('\n')); i zapętl go.

 1
Author: u0b34a0f6ae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-24 23:31:43

Może z genexps. Nie ładnie, ale...

Coś w tym stylu:

>>> gx = (line for line in '1 2 x 3 4 5 6 7 x 9 10 11 12 x 1'.split('\n'))
>>> for line in gx:
...   if line == 'x':
...      for i in range(2):
...          line = gx.next()
...   print line

Jedynym problemem jest upewnienie się, że gx może być następny () - ed. Powyższy przykład celowo generuje wyjątek z powodu ostatniego x.

 0
Author: mjv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-24 23:49:43

Dla Twojego przykładu, ponieważ pracujesz z listami (sekwencjami indeksowalnymi), a nie z iteratorami, polecam:

lines = cdata.split("\n")
for line in lines[:50]+lines[60:]:
  print line

To nie jest najbardziej wydajne, ponieważ potencjalnie tworzy 3 nowe listy (ale jeśli pominięta część jest większa niż przetworzona, może być bardziej wydajna niż inne opcje), ale jest całkiem czysta i wyraźna.

Jeśli nie masz nic przeciwko użyciu modułu itertools, możesz łatwo przekonwertować listy na sekwencje:

from itertools import chain, islice
for line in chain(islice(lines, None, 50), islice(lines, 60,None)):
  print line
 0
Author: fortran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-25 12:21:18

Nie mogę dokładnie przeanalizować pytania, ponieważ jest taki blok mylącego i nieistotnego kodu C. Proszę to usunąć.

Skupiając się tylko na kodzie Pythona i pytaniu, jak pominąć 5 linii...

lineIter= iter( cdata.splitlines() )
for line in lineIter:
  if exp.match(line):
    for count in range(5):
        line = lineIter.next()
  print line
 -6
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-25 00:41:40