Python zip和zip_之间有中间地带吗`
假设我有以下三个列表:Python zip和zip_之间有中间地带吗`,python,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)] 行为介于zip和zip\u longest之间?没有,但是您可以轻松地将和的功能结合起来以实现您想要的功能 import ite
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)]
行为介于
zip
和zip\u longest
之间?没有,但是您可以轻松地将和的功能结合起来以实现您想要的功能
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)]
from itertools import takewhile, izip_longest
from operator import itemgetter
somezip = lambda *p: list(takewhile(itemgetter(0),izip_longest(*p)))
(如果第一个迭代器的项的计算结果为False,则可以使用lambda表达式替换itemgetter-请参阅@ovgolovin的注释)
例子
>>> 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)]
定义您自己的功能:
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)]
您的输出似乎受到第一个迭代器it1的输出的限制。因此,我们可以按原样使用
it1
,用无限None
填充it2
——生成迭代器,然后使用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)]
创建无限产生None
的迭代器
粘合it2
和重复(无)
izip
将在it1
耗尽后立即停止屈服
其他解决方案也有一些缺陷(我在评论中留下了评论)。它们可能工作得很好,但如果有一些输入,它们可能会意外失败
正如注释中建议的那样,此函数更愿意接受参数中可变数量的迭代器 因此,我更新了代码以实现以下目的:
from itertools import repeat,izip,chain,imap
somezip = lambda it1,*its: izip(it1,*imap(chain,its,repeat(repeat(None))))
测试:
我不得不在这里使用imap
,尽管没有必要这样做(因为参数稍后会被解包,所以普通的map
就可以了)。原因是map
,而imap
在消耗最小迭代器时停止
因此,imap
将chain
应用于除第一个迭代器之外的所有迭代器,并且chain
使用repeat(None)
对每个迭代器进行排序。为了服务于其
的每个迭代器,我在repeat(None)
上面使用了另一个repeat
(注意,这在其他项目中可能非常危险,因为外部repeat
生成的所有对象都是相同的对象repeat(None)
,因此最终所有链
的迭代器都共享它)。然后,我解包imap
对象,生成izip
的参数,该参数返回值,直到it1
被消费(因为chain
edits
现在会生成每个值的无限序列)
请注意,所有操作都在纯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))))
这比其他的要长,但相对容易理解,如果这很重要的话 输出:
somezip(a,b):[(1,5)、(2,6)、(3,7)、(4,8)]
somezip(a,c):[(1,10),(2,11),(3,12),(4,无)]
somezip(a,g(2)):[(1,0),(2,1),(3,无),(4,无)]
somezip(g(2),a):[(1,1)]
somezip(a,b,c):[(1,5,10),(2,6,11),(3,7,12),(4,8,无)]
somezip(a,b,c,g(2)):[(1,5,10,0),(2,6,11,1),(3,7,12,无),(4,8,无,无)]
somezip(g(2),a,b,c):[(1,1,5,10)]
换句话说,一个始终取第一个参数长度的zip?@jpm:Correct。我想这是一个更好的解释,不是先调用zip\u longest
然后剪切结果吗?如果x
中的一个是无限迭代器呢?@JoachimSauer-no.list(it.islice(it.count(),10))
返回一个短列表。哦,我不知道,太好了!如果第一个迭代器不是列表,len
将进行额外的传递以确定长度。此外,它将使用迭代器。(在问题中,OP表示输入是列表。我只是想对其他人澄清这一点,他们可能会发现这个问题与他们的任务相关)。@ovgolovin:我不明白。如果x[0]
是一个生成器,比如说,你不需要额外的过程来确定长度,你会不会得到TypeError:type'generator'的对象没有len()
?如果第一个迭代器的元素计算结果为False
?如果第一个迭代器的元素计算结果为None
呢在我看来,这似乎是安全的,这个解决方案将需要为填充创建临时的唯一元素。因为如果我们使用None
,第一个列表也可以包含None
,并且我们无法区分izip__longes
返回的None
和迭代器中预先包含的None
。一个小的通用性损失是fillvalue必须是None
+1。最好的方法之一,因为它不需要调用len(it1)
。但也必须有办法支持任意数量的iterables…@glglglgl谢谢!我以为只有两个迭代器。我将为任意数量的迭代器添加代码。但是,如果我们能使其通用化,在我看来这将是一个好处,因为zip()
和izip()
和izip\u longest()
都接受超过2个…@glglglglgl我添加了可变版本!
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))))
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)