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