python任意增加循环内的迭代器
我可能会以错误的方式来解决这个问题,但是我想知道如何在Python中处理这个问题。
先来一些c代码:
int i; for(i=0;i<100;i++){ if(i == 50) i = i + 10; printf("%i\n", i); }
好,所以我们从来没有看到50年代…
我的问题是,我怎么能做类似的Python? 例如:
for line in cdata.split('\n'): if exp.match(line): #increment the position of the iterator by 5? pass print line
凭借我在Python中的有限经验,我只有一个解决scheme,引入一个计数器和另一个if语句。 打破循环,直到exp.match(行)为真后计数器达到5。
有一个更好的方法来做到这一点,希望不涉及导入另一个模块。
提前致谢!
Python中有一个叫itertools
的神奇软件包。
但在进入之前,解释一下在Python中如何实现迭代协议就好了。 当你想提供对容器的迭代时,你需要指定提供迭代器types的__iter__()
类方法。 “了解Python的”为“语句”是一篇很好的文章,介绍了for-in
语句在Python中的实际工作方式,并提供了有关迭代器types如何工作的很好的概述。
看看下面的内容:
>>> sequence = [1, 2, 3, 4, 5] >>> iterator = sequence.__iter__() >>> iterator.next() 1 >>> iterator.next() 2 >>> for number in iterator: print number 3 4 5
现在回到itertools
。 该软件包包含用于各种迭代目的的function。 如果你需要做特殊的sorting,这是第一个研究的地方。
在底部,您可以findRecipes部分,其中包含使用现有itertools作为构build块来创build扩展工具集的配方 。
还有一个有趣的function正是你所需要的:
def consume(iterator, n): '''Advance the iterator n-steps ahead. If n is none, consume entirely.''' collections.deque(itertools.islice(iterator, n), maxlen=0)
下面是一个关于它如何工作的快速可读的例子(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
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
例如,如果exp
, cdata
是:
exp = re.compile(r"skip5") cdata = """ before skip skip5 1 never see it 2 ditto 3 .. 4 .. 5 after skip 6 """
那么输出是:
在跳过之前 5跳过后 6
Python实现的C例子
i = 0 while i < 100: if i == 50: i += 10 print i i += 1
正如@ [Glenn Maynard]在评论中指出,如果你需要做一个非常大的跳转,例如i + = 100000000,那么你应该使用explicit while
循环,而不是在for
循环中跳过步骤。
下面是使用显式while
循环代替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
这个例子产生与上面的例子相同的输出。
如果你用数字来做,列表理解可以起作用:
for i in [x for x in range(0, 99) if x < 50 and x > 59]: print i
把一个迭代器向前移动有点困难。 我build议事先设置你的列表,如果你不想做计数器的方法,可能是通过拆分cdata,然后找出匹配行的索引并删除该行以及下一行。 除此之外,你还是坚持反对的态度,这种态度并不像说实话那样令人不快。
另一个select是这样的:
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
不完全确定我遵循你的思维过程,但这里有东西饲料..
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
不知道你真的以后,但范围(len(..))应该帮助你。
您可以从迭代器中删除值
def dropvalues(iterator, vals): for i in xrange(vals): iterator.next()
现在只要确保你有一个迭代器对象使用lines = iter(cdata.split('\n'))
; 并循环它。
也许与基因组。 不漂亮,但…
类似的东西:
>>> 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
唯一的问题是确保gx可以被next()编辑。 上面的例子故意由于最后一个x而产生一个exception。
对于你的例子,因为你正在处理列表(可索引序列),而不是与迭代器,我会build议如下:
lines = cdata.split("\n") for line in lines[:50]+lines[60:]: print line
这不是最有效率的,因为它可能会构造3个新列表(但是如果跳过的部分比处理的部分更大,则可能比其他选项更有效),但是它非常干净和明确。
如果您不介意使用itertools模块,则可以将列表轻松转换为序列:
from itertools import chain, islice for line in chain(islice(lines, None, 50), islice(lines, 60,None)): print line
我无法parsing这个问题,因为有这个混乱和不相关的C代码块。 请删除它。
只关注Python代码以及如何跳过5行的问题
lineIter= iter( cdata.splitlines() ) for line in lineIter: if exp.match(line): for count in range(5): line = lineIter.next() print line