よく、オンラインのプログラミングテストとかで、
標準入力から値を受け取るときに使うinput()。
今まで僕も普通にこれを使ってきたんですが、
このinput()関数が、意外と時間がかかるみたいです。
例えば、
AOJ ALDS1_3_C : Doubly Linked List
標準入力から、最大200万行くらい読み取るんですが、
はじめ、input()を使ったコードで書いていたところ、
実行時間が、最大5秒近くかかっていました。
それが、他の人の結果を見てると、
実行時間1秒以内でクリアしてる人がいたので、
どんなコードなのか見てみたところ、
(他人の提出コードも見れる。)←これいい
input()関数は使っていなくて、
sys.stdinを使っているんですよね。
それを参考にして、自分も試しに、
sys.stdinを1行ずつ読み込むようにしたところ、
他の処理はほとんど変わってないにもかかわらず、
実行時間が、最大でも1秒ちょっとに縮まりました。
それくらいになると結構効いてくるようです。
というわけで、input()関数とsys.stdinの違い。
sys.stdinを使う上で気を付ける点を、
気づいた範囲でまとめます。
入力行数がわからないとき
sys.stdinの時は、入力行数がわからなくても困りません。
例えば、下記のような入力データを読み取って、
そのまま1行ずつ出力する場合。
test1 test2 test3 test4 test5
sys.stdinを使えばこれだけでOK。
import sys for s in sys.stdin: print(s.rstrip())
これが、input()関数を使う場合は、
try~exceptでも書けばいいんですかね?
while True: try: s = input() except EOFError: break else: print(s)
でも、オンラインのプログラミングテストでは、
入力行数が与えられることがほとんどなので、
あんまりめんどくさくはならないです。
n = int(input()) # 1行目で入力行数が与えられる for i in range(n): print(input())
改行コードが取り除かれない
上記コードで、sys.stdinでは、
さりげなくrstrip()を付けたんですが、
どうやら、input()では、
末尾の改行が取り除かれるのに対して、
sys.stdinで1行ずつ読み込んだ時には、
末尾の改行コードが入ったままのようです。
rstrip()を付けなかった場合にはこうなります。
import sys for s in sys.stdin: print(s) ### 出力 ##### test1 test2 test3 test4 test5
print関数がつける行末の改行に加えて、
文字列sに含まれる改行コードもあるため、
2行ずつ改行されてしまっています。
なので、出力や計算に影響がある場合は、
この改行コードへの対策が必要。
rstrip()が確実ではあるが、
これはこれでそれなりに時間がかかる。
スライスを使うと速い。
import sys for s in sys.stdin: print(s[:-1]) ### 出力 ##### test1 test2 test3 test4 test5
また、開始位置を指定することで、
数字の部分だけを抜き出すこともできる。
import sys for s in sys.stdin: print(s[4:-1]) ### 出力 ##### 1 2 3 4 5
ただし、この[:-1]は、
行末に改行が入っていることが前提。
例えば、入力データの最終行に改行がないとこうなる。
import sys for s in sys.stdin: print(s[:-1]) ### 出力 ##### test1 test2 test3 test4 test
問題文で、入力データの制約に、
「※最終行には改行が入る」
みたいなことが書いてあればいいですが、
書いてなければ注意が必要かもしれません。
それでも、rstrip()使いたくない場合は、
import sys for s in sys.stdin: print(s[:-1] if s[-1] == "\n" else s)
だと、rstrip()を使うよりは速いっぽいです。
ただ、冒頭のリンク先の問題では通りましたが、
入力データがよくわからないときは、
改行コードが”\n”でいいかわからないので、
これはこれで危険かもですね。