質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1660閲覧

str.format()とtupleを要素に持つリストの速度差

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/08/13 09:10

編集2019/08/13 09:15

AtCoder ABC019D - Make Them Evenという問題を解いていて疑問に思ったことがあります。
今回、問題そのもののロジックは関係ありません。
この問題では複数の答えをまとめて出力することが求められるので、ansというリストを作り、そこにそれぞれの条件での答えを入れていくことにしました。
4つの数値でひとつの答えを成すので、はじめ私は ans += [(a, b, c, d)]としてタプルにまとめた形でリストに追加しました。(コード1)
ですが、他の方の解答にはstr.format()を用いた高速なものがありました。
ロジック部分を変えずに、ansへの追加方法のみをans += ["{} {} {} {}".format(a, b, c, d)]に変えたものがコード2です。
最も処理が重かったケースでそれぞれ、464msと301msかかりました。
これだけならば単なる高速化テクニックの1つに過ぎないのですが、自分で検証したところ、その速度差が再現できませんでした。
むしろ、str.formatのほうが圧倒的に遅いくらいです。(コード3)
どなたか再現ができなかった理由、あるいは一般にはリストの要素としてどちらが早いものなのか教えていただけないでしょうか?

コード1

Python

1# ABC109D - Make Them Even (tuple style) 2def main(): 3 H, W = tuple(map(int, input().split())) 4 A = list(list(map(lambda x: int(x) % 2, input().split())) for _ in range(H)) 5 ans = [] 6 for i in range(H): # move left to right 7 for j in range(W - 1): 8 if A[i][j]: 9 A[i][j] ^= 1 10 A[i][j + 1] ^= 1 11 ans += [(i + 1, j + 1, i + 1, j + 2)] 12 13 for i in range(H - 1): # move up to down 14 if A[i][W - 1]: 15 A[i][W - 1] ^= 1 16 A[i + 1][W - 1] ^= 1 17 ans += [(i + 1, W, i + 2, W)] 18 print(len(ans)) 19 for i in ans: 20 print(*i) 21 22 23if __name__ == "__main__": 24 main()

コード2

Python

1# ABC109D - Make Them Even (str-format style) 2def main(): 3 H, W = tuple(map(int, input().split())) 4 A = list(list(map(lambda x: int(x) % 2, input().split())) for _ in range(H)) 5 ans = [] 6 for i in range(H): # move left to right 7 for j in range(W - 1): 8 if A[i][j]: 9 A[i][j] ^= 1 10 A[i][j + 1] ^= 1 11 ans += ["{} {} {} {}".format(i + 1, j + 1, i + 1, j + 2)] 12 13 for i in range(H - 1): # move up to down 14 if A[i][W - 1]: 15 A[i][W - 1] ^= 1 16 A[i + 1][W - 1] ^= 1 17 ans += ["{} {} {} {}".format(i + 1, W, i + 2, W)] 18 print(len(ans)) 19 for i in ans: 20 print(*i) 21 22 23if __name__ == "__main__": 24 main()

コード3

Python

1# 実験用コードまとめ 2%%timeit 3A = [] 4for _ in range(10 ** 6): 5 A += [(1, 1, 1, 1)] 6for i in A: 7 i 8# 94.6 ms ± 4.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) 9 10%%timeit 11A = [] 12for _ in range(10 ** 6): 13 i = 1 14 A += [(i, i, i, i)] 15for i in A: 16 i 17# 167 ms ± 10.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 18 19%%timeit 20A = [] 21for _ in range(10 ** 6): 22 A += ["{} {} {} {}".format(1, 1, 1, 1)] 23for i in A: 24 i 25# 575 ms ± 5.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 26 27%%timeit 28A = [] 29for _ in range(10 ** 6): 30 i = 1 31 A += ["{} {} {} {}".format(i, i, i, i)] 32for i in A: 33 i 34# 595 ms ± 8.37 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

printにアンパックで複数の整数型要素を渡すか、単一の文字列を渡すのかで速度差が生じます。ここを省いて確認すると意味がありません。

ということで、これを試してください。確かに後者2つのほうが多少高速です。

python

1import os 2devnull = open(os.devnull, mode="w")

python

1%%timeit 2A = [] 3for _ in range(10 ** 6): 4 A += [(1, 1, 1, 1)] 5for i in A: 6 print(*i, file=devnull)

python

1%%timeit 2A = [] 3for _ in range(10 ** 6): 4 i = 1 5 A += [(i, i, i, i)] 6for i in A: 7 print(*i, file=devnull)

python

1%%timeit 2A = [] 3for _ in range(10 ** 6): 4 A += ["{} {} {} {}".format(1, 1, 1, 1)] 5for i in A: 6 print(i, file=devnull)

python

1%%timeit 2A = [] 3for _ in range(10 ** 6): 4 i = 1 5 A += ["{} {} {} {}".format(i, i, i, i)] 6for i in A: 7 print(i, file=devnull)

投稿2019/08/13 14:42

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/08/13 19:29 編集

os.devnullを初めて見たのですが、devnull = open(os.devnull, mode="w"); print(i, file=devnull)という一連の操作はprint()を使いながらも出力しないためのオプションと捉えてよいのでしょうか? ドキュメントには"The file path of the null device."としか書いてなかったもので...
退会済みユーザー

退会済みユーザー

2019/08/13 19:29

ありがとうございます!
guest

0

どなたか再現ができなかった理由、あるいは一般にはリストの要素としてどちらが早いものなのか教えていただけないでしょうか?

タプルをリストに追加するより、format() で文字列を作成してからリストに追加するほうが、フォーマットを解析して変数の値を埋め込む処理があるので、その分遅くなります。

実際、IPython の %%timeit で計測したところ、タプルをリストに追加するほうが早い結果となりました。。

python

1%%timeit 2data = [] 3for i in range(100): 4 for j in range(100): 5 data += [(i, j)] 6# 1.64 ms ± 4.36 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 7

python

1%%timeit 2data = [] 3for i in range(100): 4 for j in range(100): 5 data += ["{} {}".format(i, j)] 6# 4.15 ms ± 16.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 7

また、プログラムの可読性の面でも、最終的に print で値を出力するとはいえ、計算する段階から文字列に変換するより、タプルとしてリストに追加するほうが自然だと思います。

投稿2019/08/13 13:48

編集2019/08/13 13:49
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問