python现在,下一步,n次迭代
编写一个通用函数,该函数可以遍历返回now、next对的任何iterablepython现在,下一步,n次迭代,python,function,iterator,Python,Function,Iterator,编写一个通用函数,该函数可以遍历返回now、next对的任何iterable def now_nxt(iterable): iterator = iter(iterable) nxt = iterator.__next__() for x in iterator: now = nxt nxt = x yield (now,nxt) for i in now_nxt("hello world"): print(i)
def now_nxt(iterable):
iterator = iter(iterable)
nxt = iterator.__next__()
for x in iterator:
now = nxt
nxt = x
yield (now,nxt)
for i in now_nxt("hello world"):
print(i)
('h', 'e')
('e', 'l')
('l', 'l')
('l', 'o')
('o', ' ')
(' ', 'w')
('w', 'o')
('o', 'r')
('r', 'l')
('l', 'd')
我一直在考虑编写一个可以设置每个元组中项数的函数的最佳方法
例如,如果它是
func("hello",n=3)
结果将是:
('h','e','l')
('e','l','l')
('l','l','o')
我不熟悉使用timeit,因此如果我在这里做错了什么,请指出:
import timeit
def n1(iterable, n=1):
#now_nxt_deque
from collections import deque
deq = deque(maxlen=n)
for i in iterable:
deq.append(i)
if len(deq) == n:
yield tuple(deq)
def n2(sequence, n=2):
# now_next
from itertools import tee
iterators = tee(iter(sequence), n)
for i, iterator in enumerate(iterators):
for j in range(i):
iterator.__next__()
return zip(*iterators)
def n3(gen, n=2):
from itertools import tee, islice
gens = tee(gen, n)
gens = list(gens)
for i, gen in enumerate(gens):
gens[i] = islice(gens[i], i, None)
return zip(*gens)
def prin(func):
for x in func:
yield x
string = "Lorem ipsum tellivizzle for sure ghetto, consectetuer adipiscing elit."
print("func 1: %f" %timeit.Timer("prin(n1(string, 5))", "from __main__ import n1, string, prin").timeit(100000))
print("func 2: %f" %timeit.Timer("prin(n2(string, 5))", "from __main__ import n2, string, prin").timeit(100000))
print("func 3: %f" %timeit.Timer("prin(n3(string, 5))", "from __main__ import n3, string, prin").timeit(100000))
结果:
$ py time_this_function.py
func 1: 0.163129
func 2: 2.383288
func 3: 1.908363
我的建议是,
from collections import deque
def now_nxt_deque(iterable, n=1):
deq = deque(maxlen=n)
for i in iterable:
deq.append(i)
if len(deq) == n:
yield tuple(deq)
for i in now_nxt_deque("hello world", 3):
print(i)
('h', 'e', 'l')
('e', 'l', 'l')
('l', 'l', 'o')
('l', 'o', ' ')
('o', ' ', 'w')
(' ', 'w', 'o')
('w', 'o', 'r')
('o', 'r', 'l')
('r', 'l', 'd')
我的解决方案:
def nn(itr, n):
iterable = iter(itr)
last = tuple(next(iterable, None) for _ in xrange(n))
yield last
for _ in xrange(len(itr)):
last = tuple(chain(last[1:], [next(iterable)]))
yield last
这是为Python2设计的,如果您想将其与Python3一起使用,请将xrange
替换为range
next
,有一个很棒的default
参数,它将被返回,而不是引发StopIteration
,您还可以将此默认参数添加到函数中,如下所示:
def nn(itr, n, default=None):
iterable = iter(itr)
last = tuple(next(iterable, default) for _ in xrange(n))
yield last
for _ in xrange(len(itr)):
last = tuple(chain(last[1:], [next(iterable, default)]))
yield last
我还玩了一些,例如使用
itr.\uuuu class\uuuu()
作为默认值,但这对于列表和元组来说似乎是错误的,对于字符串来说才有意义 这里有一个非常简单的方法:
- 使用克隆迭代器
次n
- 将
th迭代器i
提前几次i
izip
Eric使用切片技术的变体
from itertools import tee, islice, izip
def now_next(gen, n=2):
gens = tee(gen, n)
gens = list(gens)
for i, gen in enumerate(gens):
gens[i] = islice(gens[i], i, None)
return izip(*gens)
for x in now_next((1,2,3,4,5,6,7)):
print x
基于cravoori回答的一行:
from itertools import tee, islice, izip
def now_next(gen, n=2):
return izip(*(islice(g, i, None) for i, g in enumerate(tee(gen, n))))
我觉得不错。我可以尝试通过使用两个循环来摆脱len()检查:一个循环使用前n-1项初始化deque,然后使用一个循环生成完整的元组。但是我也可以用一个循环来决定它是更好的。你可能会想问一个问题“如何做到这一点”,然后把你的东西作为一个答案,而不是把它放在问题上。@ Lattyware,谢谢你的建议!这绝对是一个紧凑的解决方案。
len(itr)
不适用于生成器,这会降低通用性。你是对的,所以我试图找到一个更好的方法,我记住了itertools文档,我编辑了post.OP想要重叠的子序列,而不是grouper
生成的子序列。正确,我删除了它,我的错误。伟大的解决方案!只有一个想法:既然你是从迭代器开始的,也许坚持这种模式并在最后返回itertools.izip(*iterators)是有意义的?@jathanism:good point。为了清楚起见,我只需输入zip
。已编辑。@Eric,此方法的可伸缩性如何?克隆迭代器会有很大的成本吗?@Themanntheclaphamnibus:不确定。克隆迭代器比克隆集合要好!我不确定我的解决方案是否比你的解决方案更好。你不应该使用iterator.next()
而应该使用next(iterator)
。这似乎比Erics快,我已将函数添加到问题中的timeit列表中。-注意,当我使用Python3.X时,izip现在是zip
from itertools import tee, islice, izip
def now_next(gen, n=2):
return izip(*(islice(g, i, None) for i, g in enumerate(tee(gen, n))))