【python3】リストの要素をn回繰り返すスマートな方法

やりたいこと

 以下のようなリストがあるとします。

[1, 2, 3, 4]

 これを、以下のように循環させたい場合どうすればいいでしょうか。

[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]

解決方法

 以下のような結果を標準出力に表示することを想定します。これは、[1, 2, 3, 4]のリストを3回繰り返したシンプルなものです。

1
2
3
4
1
2
3
4
1
2
3
4

普通にfor-loopで回す

 シンプルです。

REPEAT_COUNT = 3
l = [1, 2, 3, 4]

for n in range(REPEAT_COUNT):
  for elem in l:
    print(elem)

 変に小技を使っていない分readableですし、余計な要素を作成することもありません。ループするだけならこれで十分です。

*演算子を利用する

 * 演算子をリストに利用すれば要素を繰り返させることができます。listに対する演算子の動きさえ知っていれば直感的に見えます。

REPEAT_COUNT = 3
l = [1, 2, 3, 4]
l *= REPEAT_COUNT

for elem in l:
  print(elem)

 しかし、これは繰り返し回数分のshallow copyを作成しているという指摘があります。普段遣いではこれで問題ないでしょうが、多くの要素を含んだlistを操作するときや、多くの回数を繰り返す場合は注意が必要です。

itertoolsを使う

 pythonのbuild-inライブラリであるitertoolsには色々な便利メソッドが多数組み込まれています。それに、これらは、多くの場合generatorに似た性質を持っているので、過度にパフォーマンスやメモリを気にする必要が無いのが嬉しいポイントです。

 では早速実装してみましょう。

from itertools import chain, repeat
REPEAT_COUNT = 3
l = [1, 2, 3, 4]

for elem in chain.from_iterable(repeat(l, REPEAT_COUNT)):
  print(elem)

 賛否が分かれるところですが、repeatでlist自体を循環させ、chainでそれらをflattenしている、といったイメージになります。直感的に分かりづらいかもしれませんが、そこそこ及第点くらいのスマートさはありそうです。

無限回繰り返したいなら…?

 ほぼ以下が最適解です。

 その名の通り無限ループするので実行には注意してください。(対話シェルならCtrl+Cで止まってはくれるようです)

from itertools import cycle
l = [1, 2, 3, 4]

for elem in cycle(l):
  print(elem)

 while(True)みたいなことをしてもいいですが、next()は使えなくなります。

まとめ

 どれを使ってもよいと思いますが、注意が必要なものもありますので、適切に判断の上使ってみてください。next()が必要なければrangeを利用すればよいし、そうでなければitertoolsを使うのがよさそうです。あるいは、繰り返し数や要素が将来に渡りそこまで多くないことが保証されているなら、*演算子を利用した方法でも構わないと思います。