リストをタプルにしたり、その逆にタプルをリストにするのはよくある要求です。
一般的な方法
一般的なのは組み込み関数のlist
およびtuple
を使用することです。
l = [0, 1, 2]
t = tuple(l)
print(t)
(0, 1, 2)
この方法の問題
ところが、リストがネストしていた場合、最も浅い階層しかタプルにしてくれません。
l = [[0, 1, 2], [3, 4, 5, 6, 7], 8, 9]
t = tuple(l)
print(t) # ((0, 1, 2), (3, 4, 5, 6, 7), 8, 9) になってほしい
([0, 1, 2], [3, 4, 5, 6, 7], 8, 9)
キレそ。
ネストしたリストを内部ごとタプルにする関数
再帰呼び出ししながら全階層タプルにしてやりましょう。
def list_to_tuple(l):
return tuple(list_to_tuple(e) if isinstance(e, list) else e for e in l)
l = [[0, 1, 2], [3, 4, 5, 6, 7], 8, 9]
t = list_to_tuple(l)
print(t)
((0, 1, 2), (3, 4, 5, 6, 7), 8, 9)
やったぜ。
元ネタとその比較
実はこの記事はこちらのパクリです。 お前恥ずかしくないのかよ
違いとしましては、むこうでは for 文と代入演算子を使用していた部分を内包表記にしたことです。
愚直に繰り返す for 文に対して、内包表記は専用の処理を呼び出してくれるため実行時間が短くなります (参考)。
def list_to_tuple_orig(_list):
t = ()
for e in _list:
if isinstance(e,list):
t += (list_to_tuple(e),)
else:
t += (e,)
return t
l = list(range(10000))
%timeit t = list_to_tuple_orig(l)
%timeit t = list_to_tuple(l)
%timeit t = tuple(l)
92.7 ms ± 576 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
877 µs ± 3.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
19.6 µs ± 47.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
100 倍くらい早くなっていますね。 組み込み関数には大敗北ですが。