Python ループ処理の最初と最後を判定する

Pythonでループ処理をしている際に、最初や最後を判定する方法についてまとめました。

最初を判定

まず最初についての判定です。
range関数を繰り返す場合を考えてみます。

for i in range(5):
    if i == 0:
        print(f'最初:{i}')
    else:
        print(f'途中:{i}')
>>>
最初:0
途中:1
途中:2
途中:3
途中:4


これは動作しますが、ちょっとカッコ悪いです。
例えばrange関数を繰り返すのではなくて、普通のリストを繰り返すにはどうなるでしょうか?

my_list = ['first', 'second', 'third']
for i, val in enumerate(my_list):
    if i == 0:
        print(f'最初:{val}')
    else:
        print(f'途中:{val}')
>>>
最初:first
途中:second
途中:third


普通のリストを繰り返す場合にわざわざenumurate関数を呼ぶことになってしまいました。
なので、以下のように変数を作った方が直感的でわかりやすいです。

my_list = ['first', 'second', 'third']
first = True
for val in my_list:
    if first:
        print(f'最初:{val}')
        first = False
    else:
        print(f'途中:{val}')
>>>
最初:first
途中:second
途中:third


最後を判定

最後の判定は少し難しいです。
range関数では以下のような形でしょうか。

last_count = 5
for i in range(last_count):
    if i == last_count - 1:
        print(f'最後:{i}')
    else:
        print(f'途中:{i}')
>>>
途中:0
途中:1
途中:2
途中:3
最後:4


普通のリストではやはりenumurate関数を使う形になると思います。

my_list = ['first', 'second', 'third']
for i, val in enumerate(my_list):
    if i == len(my_list) - 1:
        print(f'最後:{val}')
    else:
        print(f'途中:{val}')
>>>
途中:first
途中:second
最後:third


両方ともあまり直感的ではないです。
特にリストを繰り返す方については、enumurate(my_list,1)という風にカウントを0以外で始まるように指定していたら、途端に意図しない結果になります。

my_list = ['first', 'second', 'third']
for i, val in enumerate(my_list, 1):
    if i == len(my_list) - 1:
        print(f'最後:{val}')
    else:
        print(f'途中:{val}')
>>>
途中:first
最後:second
途中:third


処理の最後の判定については、色々と議論がされており、代表的なものを紹介します。

iter関数で判定


def lookahead(iterable):
    it = iter(iterable)
    # ループを一個進めておいて、lastに最初の値を代入
    last = next(it)
    # secondとthirdを取り出す
    for val in it:
        yield last, True
        # lastに代入
        last = val
    # 最後にyield
    yield last, False


my_list = ['first', 'second', 'third']

for i, has_more in lookahead(my_list):
    if has_more:
        print(f'途中:{i}')
    else:
        print(f'最後:{i}')
>>>
途中:first
途中:second
最後:third


汎用的に使えそうですが、関数を別に設けるのが難点でしょうか。

事前にスライスしたものを繰り返す


事前に最後の要素だけを残してスライスを行い繰り返します。
繰り返しが終わった後に、最後の要素にのみ処理を施す形です。

for val in my_list[:-1]:
    print(f'途中:{val}')
print(f'最後:{my_list[-1]}')
>>>
途中:first
途中:second
最後:third


こちらは短くてわかりやすいですね。

while文で判定する


listの値がなくなるまでpop関数で順番に取り出す方法です。

while my_list:
    val = my_list.pop(0)
    if my_list:
        print(f'途中:{val}')
    else:
        print(f'最後:{val}')
>>>
途中:first
途中:second
最後:third


ただし、取り出した後はmy_listの値が空になるので、注意が必要です。

print(my_list)
>>>
[]


TOPページ