連番は急に欲しくなることが知られている。
データの処理、ループの制御、ファイル名の生成といった用途で連続した整数のリストはとても役に立つ。
range()とリスト内包表記
基本的には range() が手軽で良い。
# range(N) は 0 オリジンの連番を作る
for i in range(3):
print(f"{i}")
# 0
# 1
# 2
# range(N,M) は N から M -1 の区間の連番を作る
# range(N,M) の終了は M ではなく M - 1 であることに注意
for i in range(1,13):
print(f"{i}月")
# 1月
# 2月
# 3月
# 4月
# 5月
# 6月
# 7月
# 8月
# 9月
# 10月
# 11月
# 12月
ただし、 range(N) の返り値は range 型なので list[int] 型がほしいときは list() を使う。
print(type(list(range(10)))) # <class 'list'>
print(type(range(10))) # <class 'range'>
奇数がほしいなど注文がある場合はリスト内包表記が便利だ。
# 2 の倍数を飛ばしている
[i for i in range(10) if i%2!=0] # [1, 3, 5, 7, 9]
使用例:ディレクトリが揃っているか確認する
次のようなディレクトリがあるのを想像してほしい。このディレクトリは 1957 年から 1988 年の記事を年度ごとに直下のディレクトリにファイリングしている。
ls.txt
$ ls
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1971 1972 1973 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
70 年代を見れば分かるように、いくつかあるべきディレクトリが抜けている。このくらいの数ならディレクトリを人力で数えてもいいだろう、ただ数が増えると間違えることはわかる。
わかりきった問題なら、年数が増えても良いようにあらかじめプログラムで解決しておこう。
次のプログラムは 1957-89 区間の連続した(serial)な年リストと当該ディレクトリのリストの差を求めるプログラムだ。そしてその差分こそが欠落した年のリストである。
"""欠落しているディレクトリを求めるプログラム"""
DIR:str = "1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1971 1972 1973 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988"
# DIR.split() だと文字列のリストになるので型を変換する
dirs:list[int] = [int(i) for i in DIR.split()]
serial:list[int] = list(range(1957,1989))
lacked_dirs:list[int] = [i for i in serial if i not in dirs]
print(lacked_dirs)
# [1969, 1970, 1974, 1975, 1976, 1977]
結論
- print するなら range() を、変数に投げ込むならリスト内包表記を使うと良い
- 複雑な条件分岐をするならば、リスト内包表記は読みづらくなるので使うべきではない
Link
-
5. データ構造 — Python 3.11.5 ドキュメント
- リスト内包表記についての公式ドキュメント
-
組み込み型 — Python 3.11.5 ドキュメント
- range() についての公式ドキュメント