在`zip`和`zip_longest`之间是否存在中间立场

时间:2012-11-12 09:33:09

标签: python

说我有这三个清单:

a = [1, 2, 3, 4]
b = [5, 6, 7, 8, 9]
c = [10, 11, 12]

是否有内置函数:

somezip(a, b) == [(1, 5), (2, 6), (3, 7), (4, 8)]
somezip(a, c) == [(1, 10), (2, 11), (3, 12), (4, None)]

zipzip_longest之间的某个位置?

5 个答案:

答案 0 :(得分:8)

没有,但您可以轻松地将takewhileizip_longest的功能结合起来,以实现您的目标

from itertools import takewhile, izip_longest
from operator import itemgetter
somezip = lambda *p: list(takewhile(itemgetter(0),izip_longest(*p)))

(如果第一个迭代器可能包含评估为False的项,则可以用lambda表达式替换itemgetter - 请参阅@ ovgolovin的注释)

somezip = lambda *p: list(takewhile(lambda e: not e[0] is None,izip_longest(*p)))

实施例

>>> from itertools import takewhile, izip_longest
>>> from operator import itemgetter
>>> a = [1, 2, 3, 4]
>>> b = [5, 6, 7, 8, 9]
>>> c = [10, 11, 12]
>>> somezip(a,b)
[(1, 5), (2, 6), (3, 7), (4, 8)]
>>> somezip(a,c)
[(1, 10), (2, 11), (3, 12), (4, None)]
>>> somezip(b,c)
[(5, 10), (6, 11), (7, 12), (8, None), (9, None)]

答案 1 :(得分:5)

import itertools as it

somezip = lambda *x: it.islice(it.izip_longest(*x), len(x[0]))



>>> list(somezip(a,b))
[(1, 5), (2, 6), (3, 7), (4, 8)]

>>> list(somezip(a,c))
[(1, 10), (2, 11), (3, 12), (4, None)]

答案 2 :(得分:3)

您的输出似乎受第一个迭代器it1的输出限制。因此,我们可以按原样使用it1,并使用无限it2填充None - 产生迭代器,并zip

>>> from itertools import repeat,izip,chain
>>> somezip = lambda it1,it2: izip(it1,chain(it2,repeat(None)))

>>> list(somezip(a,b))
[(1, 5), (2, 6), (3, 7), (4, 8)]
>>> list(somezip(a,c))
[(1, 10), (2, 11), (3, 12), (4, None)]

repeat(None)创建迭代器,无限地产生None

chain粘合it2repeat(None)

<izip将在it1耗尽后立即停止屈服。

其他解决方案存在一些缺陷(我在评论中留下了评论)。它们可能运行良好,但有些输入可能会意外失败。


在注释中建议 glglgl ,此函数宁愿接受参数中可变数量的迭代器。

所以我更新了代码来实现这个目的:

from itertools import repeat,izip,chain,imap
somezip = lambda it1,*its: izip(it1,*imap(chain,its,repeat(repeat(None))))

测试:

>>> print(list(somezip(a,b)))
    print(list(somezip(a,c)))
    print(list(somezip(b,a,c)))

[(1, 5), (2, 6), (3, 7), (4, 8)]
[(1, 10), (2, 11), (3, 12), (4, None)]
[(5, 1, 10), (6, 2, 11), (7, 3, 12), (8, 4, None), (9, None, None)]

我不得不在这里使用imap,虽然没有必要这样做(因为参数后来被解压缩,所以普通map会这样做)。原因是map don't accept iterators of different length,而imap在消耗最小迭代器时停止。

因此,imapchain应用于所有迭代器,除了第一个和chain,每个迭代器都使用repeat(None)。要为its的每个迭代器提供服务,我在repeat之上使用了另一个repeat(None)(注意,在其他项目中,它可能非常危险,因为外部repeat生成的所有对象是同一个对象repeat(None),所以最后它们所有的chain ed迭代器共享它。然后我解压缩imap对象以生成izip的参数,该参数返回值,直到it1被消耗(因为chain ed its现在产生无限序列每个价值观。)

请注意,所有操作都在纯C中工作,因此不涉及解释器开销。

为了澄清它是如何工作的,我正在补充这个细节:

def somezip(it1,*its): #from 0 to infinite iterators its
    # it1 -> a1,a2,a3,...,an
    # its -> (b1,b2,b3,...,bn),(c1,c2,c3,...,cn),...
    infinite_None = repeat(None) # None,None,None,...
    infinite_Nones = repeat(infinite_None) # infinite_None,infinite_None,... (share the same infinite_None)
    chained = imap(chain,its,infinite_Nones) # [(b1,b2,b3,...,bn,None,None,...),(c1,c2,c3,...,cn,None,None,...),...]
    return izip(it1,*chained)

并且它的单行只是:

somezip = lambda it1,*its: izip(it1,*imap(chain,its,repeat(repeat(None))))

答案 3 :(得分:0)

定义你自己的功能:

In [64]: def myzip(*args):
    lenn=len(args[0])
    return list(izip_longest(*[islice(x,lenn) for x in args],fillvalue=None))
   ....: 

In [30]: myzip(a,b)
Out[30]: [(1, 5), (2, 6), (3, 7), (4, 8)]

In [31]: myzip(b,c)
Out[31]: [(5, 10), (6, 11), (7, 12), (8, None), (9, None)]

In [32]: myzip(a,c)
Out[32]: [(1, 10), (2, 11), (3, 12), (4, None)]

答案 4 :(得分:0)

这比其他人长,但相对容易理解,如果重要的话。 ; - )

a = [1, 2, 3, 4]
b = [5, 6, 7, 8, 9]
c = [10, 11, 12]
def g(n): return xrange(n)  # simple generator

def my_iter(iterable, fillvalue=None):
    for i in iterable: yield i
    while True: yield fillvalue

def somezip(*iterables, **kwds):
    fillvalue = kwds.get('fillvalue')
    iters = [my_iter(i, fillvalue) for i in iterables]
    return [tuple(next(it) for it in iters) for i in iterables[0]]

print 'somezip(a, b):', somezip(a, b)
print 'somezip(a, c):', somezip(a, c)
print 'somezip(a, g(2)):', somezip(a, g(2))
print 'somezip(g(2), a):', somezip(g(2),a)
print 'somezip(a, b, c):', somezip(a, b, c)
print 'somezip(a, b, c, g(2)):', somezip(a, b, c, g(2))
print 'somezip(g(2), a, b, c):', somezip(g(2), a, b, c)

输出:

somezip(a, b): [(1, 5), (2, 6), (3, 7), (4, 8)]
somezip(a, c): [(1, 10), (2, 11), (3, 12), (4, None)]
somezip(a, g(2)): [(1, 0), (2, 1), (3, None), (4, None)]
somezip(g(2), a): [(1, 1)]
somezip(a, b, c): [(1, 5, 10), (2, 6, 11), (3, 7, 12), (4, 8, None)]
somezip(a, b, c, g(2)): [(1, 5, 10, 0), (2, 6, 11, 1), (3, 7, 12, None), (4, 8, None, None)]
somezip(g(2), a, b, c): [(1, 1, 5, 10)]