交替并迭代不同长度的多个迭代器而不停止

时间:2015-04-30 21:44:19

标签: python exception iteration

以下是一个例子:

try
{
    $db = new PDO('sqlite:norming_database.db');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
    echo $e->getMessage();
}

/*... some other stuff in between ...*/

try
{
    $query = "SELECT stimulusName
            FROM responses
            WHERE workerId LIKE :workerId";
    $stmt = $db->prepare($query);
    $stmt->bindParam(':workerId', $_GET['testWorkerId']);
    $stmt->execute();
    $result = $stmt->fetch();
}
catch(PDOException $e)
{
    echo "PDO Error: " . $e->getMessage();
}

echo "<pre>" . var_dump($result) . "</pre>";

这是我到目前为止所做的:

for i in f('abcde','fg','hijk'):
print(i,end='')
#should print out
afhbgicjdke

使用相同的示例,这就是我要打印的内容:

def f(*args):
    arg_list = [argument for argument in args]
    iter_list = []
    for arg in arg_list:
        iter_list.append(iter(arg))

    try:
        while True:
            for i in iter_list:
                yield next(i)
    except StopIteration:
        iter_list.remove(i)
        for i in reversed(iter_list):
            yield next(i)

我无法弄清楚如何处理此StopIteration错误。我试图在不使用itertools

的情况下实现这一点

3 个答案:

答案 0 :(得分:2)

这是izip_longest的应用程序。

from itertools import chain, izip_longest
''.join(chain.from_iterable(izip_longest('abcde', 'fg', 'hijk', fillvalue='')))

输出:

'afhbgicjdke'

在这个例子中,它将三个序列压缩成三个元素的元组。如果我们的某个序列没有相应的元素,我们使用默认值''。然后我们使用chain.from_iterable展平了那些元组,最后我们将所有角色加在一起。

如果我们只允许使用基本功能,我们可以这样做:

def f(*args):
    n = len(args)
    iters = map(iter, args)
    exhausted = [False] * n
    while n > 0:
        for i, it in enumerate(iters):
            if not exhausted[i]:
                try:
                    yield next(it)
                except StopIteration:
                    exhausted[i] = True
                    n -= 1

print ''.join(f('abcde', 'fg', 'hijk'))

使用此代码,我们可以跟踪耗尽的迭代器。当 live 的数量达到零时,我们停止生成器。如果迭代器耗尽,那么下次我们不会检查它。

答案 1 :(得分:2)

一个不使用itertools或压缩的简单解决方案(也不会尝试嵌入压缩实现):

def f (*args):
    maxLen = max(map(len, args))
    for i in range(maxLen):
        for arg in args:
            if i < len(arg):
                yield arg[i]

对于任何可迭代:

def f (*args):
    args = [iter(arg) for arg in args]
    while True:
        yielded = False
        for arg in args:
            x = next(arg, None)
            if x is not None:
                yielded = True
                yield x
        if not yielded:
            break
>>> list(f(range(3), range(3, 5), range(5, 10)))
[0, 3, 5, 1, 4, 6, 2, 7, 8, 9]

答案 2 :(得分:0)

这是a recipe in the itertools documentation

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).next for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))

例如,使用IPython REPL:

In [19]: from itertools import *

In [20]: def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).next for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))
   ....:                     

In [21]: "afhbgicjdke" == "".join(roundrobin('abcde','fg','hijk'))
Out[21]: True