首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从几个可迭代项中交错值

从几个可迭代项中交错值
EN

Code Review用户
提问于 2015-01-25 16:12:44
回答 2查看 1.5K关注 0票数 6

我是Python新手,我想看看是否有一种更干净的方法来编写我的代码。下面的代码将可迭代性作为参数,它从第一个参数生成第一个值,然后从第二个参数生成第一个值,然后从最后一个参数生成第一个值;然后从第一个参数生成第二个值,因此on.If任何可迭代的值都不会产生更多的值,这个生成器不会产生更多的值。

如果我这样做了:

代码语言:javascript
复制
for i in skip('abcde','fg','hijk'):
  print(i,end='')

生成值'a‘、'f’、'h‘、'b’、'g‘、'i’和'c‘。我编写的代码如下(该代码起作用):

代码语言:javascript
复制
def skip(*args):
  itrs = [iter(arg) for arg in args]
  while itrs != []: 
     temp = [] 
     for i in range(len(itrs)): 
        try: 
          yield next(itrs[i]) 
          temp.append(itrs[i]) 
        except StopIteration: 
          pass
      itrs = temp

是否有一种更简洁的方法来编写代码(而不使用任何外部库)?

EN

回答 2

Code Review用户

回答已采纳

发布于 2015-01-25 17:35:30

首先,我认为原始代码中有一个错误。代码生成afhbgicjdke而不是预期的afhbgic。我认为意图是在停止迭代块中使用return而不是pass,下面的答案是在这种假设下工作的。

让我们看看中间的for循环

代码语言:javascript
复制
for i in range(len(itrs)):
    try:
        yield next(itrs[i])
        temp.append(itrs[i])
    except StopIteration:
        return

不对索引进行操作,所以每个itrs[i]都可以用一个更简单的for i in iters替换为i。这给了我们

代码语言:javascript
复制
for i in itrs:
    try:
        yield next(i)
        temp.append(i)
    except StopIteration:
        return

现在让我们看一下while主体

代码语言:javascript
复制
while itrs != []:
    temp = []
    # ... the for loop that includes an append to itrs
    itrs = temp

这基本上为代码提供了一种在一切完成后退出的方法。但是,如果您考虑代码是如何工作的,itrs的长度只有当一个itrs到达StopIteration时才会比args短。如果那样的话,我们早就回来了!

这样,while循环就可以变成while循环和temp,并且它的使用也就可以完全满足了。

代码语言:javascript
复制
def skip(*args):
    itrs = [iter(arg) for arg in args]
    while True:
        for i in itrs:
            try:
                yield next(i)
            except StopIteration:
                return

现在我们需要说服自己,代码会在某个时候返回。这并不是太难,只要其中一个可迭代传入是有限的,即有一个结束,我们将在某个时候到达StopIteration。在每一个可迭代性都是无限的情况下,原始代码也将永远运行。所以我们在那里很好。

但还有另一个问题。如果调用skip时没有任何参数,该怎么办?这将导致我们永远不会从函数返回,因为我们没有可迭代的触发StopIteration!在原始代码中,这是通过temp为空隐式处理的。既然我们已经没有它了,我们必须明确地处理它。这给了我们最后的代码:

代码语言:javascript
复制
def skip(*args):
    if len(args) == 0:
        return
    itrs = [iter(arg) for arg in args]
    while True:
        for i in itrs:
            try:
                yield next(i)
            except StopIteration:
                return

有了这个

代码语言:javascript
复制
for i in skip('abcde','fg','hijk'):
    print(i,end='')

输出afhbgic

代码语言:javascript
复制
for i in skip():
    print(i,end='')

是个圆头

另外,原始代码中的缩进是不一致的,这使得它无法运行.请确保下次发布可用代码。

票数 7
EN

Code Review用户

发布于 2015-01-25 20:36:48

您说过不使用外部库,但是如果您可以使用Python标准库,那么您几乎可以使用cycle函数从可迭代的迭代器上使用itertools来做您想做的事情:

代码语言:javascript
复制
from itertools import cycle

def skip(*args):
    return (next(i) for i in cycle(iter(arg) for arg in args))

或者更简洁的Python 3版本:

代码语言:javascript
复制
from itertools import cycle

def skip(*args):
    return map(next, cycle(map(iter, args)))

Python 2的简化版本也是相同的:

代码语言:javascript
复制
from itertools import cycle, imap

def skip(*args):
    return imap(next, cycle(imap(iter, args)))

在任何情况下,您都不需要在生成器中捕获Python2中的StopIteration:抛出它会自动结束生成器并被调用方捕获。因此,即使没有itertools,您也可以这样做:

代码语言:javascript
复制
def skip(*args):
    if not args:
        return
    iters = [iter(arg) for arg in args]
    while True:
        for it in iters:
            yield next(it)

根据@XrXrXr的评论,由于Python3.5中的cycle冒泡,使用StopIteration的解决方案将变成:

代码语言:javascript
复制
def skip(*args):
    try:
        yield from (next(i) for i in cycle(iter(arg) for arg in args))
    except StopIteration:
        return
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/78549

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档