次の 3 つのリストがあるとします。
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_longest
ますか?
次の 3 つのリストがあるとします。
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_longest
ますか?
いいえ、ありませんが、takewhileとizip_longestの機能を簡単に組み合わせて、必要なものを実現できます
from itertools import takewhile, izip_longest
from operator import itemgetter
somezip = lambda *p: list(takewhile(itemgetter(0),izip_longest(*p)))
(最初のイテレータに False と評価されるアイテムがある場合、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)]
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)]
出力は、最初のイテレータの出力によって制限されているよう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
接着剤it2
とrepeat(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
長さのイテレータを受け入れないためです。imap
したがって、最初のイテレータを除くすべてのイテレータにimap
適用され、それぞれに。が付いています。上記のすべてのイテレータにサービスを提供するために、上記の別のイテレータを使用しました(他のプロジェクトでは、外部が生成するすべてのオブジェクトが同じオブジェクトであるため、最終的にはすべての編集者がそれを共有するため、非常に危険な場合があります)。次に、オブジェクトを解凍してパラメータをに生成します。これにより、消費されるまで値が返されます( edは、それぞれ無限の値のシーケンスを生成するようになりました)。chain
chain
repeat(None)
its
repeat
repeat(None)
repeat
repeat(None)
chain
imap
izip
it1
chain
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))))
独自の関数を定義します。
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)]
これは他のものよりも長いですが、それが重要な場合は比較的簡単に理解できます. ;-)
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)]