この以前のスタック オーバーフローの質問に触発されて、各イテラブル内の要素の順序を維持しながら、Python でイテラブルをランダムにインターリーブする方法を検討してきました。例えば:
>>> def interleave(*iterables):
... "Return the source iterables randomly interleaved"
... <insert magic here>
>>> interleave(xrange(1, 5), xrange(5, 10), xrange(10, 15))
[1, 5, 10, 11, 2, 6, 3, 12, 4, 13, 7, 14, 8, 9]
元の質問は、2 つのリスト a と b をランダムにインターリーブするように求められ、受け入れられた解決策は次のとおりです。
>>> c = [x.pop(0) for x in random.sample([a]*len(a) + [b]*len(b), len(a)+len(b))]
ただし、このソリューションは 2 つのリストに対してのみ機能し (簡単に拡張できます)、a と b がリストであるという事実に依存しているため、それらに対してpop()
およびlen()
を呼び出すことができます。つまり、イテラブルでは使用できません。また、ソース リスト a と b を空にするという不幸な副作用もあります。
元の質問に対して与えられた代替回答は、ソースリストのコピーを取得して変更を回避しますが、特にソースリストがかなり大きい場合、これは非効率的だと思います。代替の回答も利用するためlen()
、単なるイテラブルでは使用できません。
任意の数の入力リストに対して機能し、それらを変更しない独自のソリューションを作成しました。
def interleave(*args):
iters = [i for i, b in ((iter(a), a) for a in args) for _ in xrange(len(b))]
random.shuffle(iters)
return map(next, iters)
ただし、このソリューションは、ソース引数がリストであることに依存しているため、len()
それらで使用できます。
それで、事前にイテラブルの長さを知る必要がなく、イテラブルのコピーを取らない、要素の元の順序を維持しながら、Pythonでイテラブルをランダムにインターリーブする効率的な方法はありますか?
編集:元の質問と同様に、公平にするためにランダム化は必要ないことに注意してください。