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

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

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

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

Q&A

解決済

4回答

3189閲覧

Python3 for文を内包表記に書き換えたい(実装可能?)

opyon

総合スコア1009

Python 3.x

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

0グッド

1クリップ

投稿2018/10/07 04:55

編集2018/10/07 06:04

for文より内包表記の方が速いらしいのでなるべく内包表記にしようと練習しています。
どうしたいかを伝えるのにもっとシンプルなサンプル書ければ良いのですがすみません。

####知りたいこと
以下のサンプルコードのfor文を内包表記に書き換えたいのですが疑問が生じました。
もしかすると内包表記では終端処理的なことは1つしか書けないのでしょうか?
例えば途中で変数をカウントアップしながら最後にリストを作るなど。
出来ないなら出来ないという回答でも構いませんのでご教示頂ければ助かります。
(出来るよ!のヒントだけでも構いません。)

####試したこと
サンプルコードの中の count += 1 の部分をどのように組み込めばよいのか分からず当てずっぽうで入れて
みても動きませんでした。
現状では内包表記でリスト出力までは出来たものの同時にカウントする方法が分からずそのままです。

現状のサンプルコード

python

1#普通のfor文 2count = 0 3for i in range(10): 4 if i % 2 ==1: 5 for j in range(5): 6 if j % 2 ==1: 7 count += 1 8 print(i*10 +j,end = ' ') 9print('count:',count) 10 11#内包表記 12count = 0 13print(*[i*10 +j for i in range(10) if i % 2 == 1 for j in range(5) if j % 2 == 1],end = ' ') 14print('count:',count) 15

python

1出力結果 211 13 31 33 51 53 71 73 91 93 count: 10 311 13 31 33 51 53 71 73 91 93 count: 0 ←※未実装なので0のままです

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

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

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

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

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

guest

回答4

0

ベストアンサー

for文より内包表記の方が速いらしい

処理内容によりますが、基本的に内包表記にしたからといってそんな劇的に高速化が為される訳ではありません。それに、内包表記よりnumpyやcythonの方が速い訳だし。

可読性を捨ててまで内包表記にする必要はないです・・・

ちなみにリスト内包表記そのものはチューリング完全なので、「可能か?」と問われればにっこり笑って「可能です」と答えられます。

参考:
リスト内包表記の活用と悪用
Pythonのリスト内包表記はチューリング完全だから純LISPだって実装できる


汚いけどすぐ思いつく方法でやってみた。実用を意図している訳ではないので注意。

python

1count = 0 2print(*[(i*10 +j, globals().__setitem__("count", globals()["count"]+1))[0] for i in range(10) if i % 2 == 1 for j in range(5) if j % 2 == 1],end = ' ') 3print('count:',count)

投稿2018/10/07 06:08

編集2018/10/07 06:48
hayataka2049

総合スコア30933

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

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

opyon

2018/10/07 07:05

いつもありがとうございます。 出来ないと予想していたので出来ることに驚いています。 なるほど!単純にカンマで区切れば2つの処理が出来たのですね。 globals()というものがあるのですね。 私が書いた関数内のglobalとご親戚でしょうか・・・ >実用を意図している訳ではないので注意。 for文で書けてるので大丈夫ですが、 内包表記の練習での質問なのにお手数お掛けしました^^; >可読性を捨ててまで内包表記にする必要はないです・・・ 無理に内包表記しようとしてる訳ではないですが、少しでも速さを求められる問題がこれから増えそうなのと、numpyが使えない某サイトの問題などもあるので使えて損はないかなと思いました。
hayataka2049

2018/10/07 07:12

カンマで区切れば、というか、tupleの中に複数の式を入れて後から必要なものだけ取り出している訳ですね globals()はグローバル変数辞書を返す組み込み関数です __setitem__は辞書のメソッド。使いかたは見たとおりです
opyon

2018/10/07 07:16

ああ、なるほど!それで後ろに[0]がついてるのですね。見落としていました。 (処理1,処理2)[0] 処理1の結果をget!
KNaito

2018/10/07 08:37

横からすみません。なるほど、globals()などを使って書き換えればいけるんですね。
KNaito

2018/10/07 08:41

hayataka2049 さんの回答のように、内包表記でもglobals().__setitem__を使えば、グローバル変数も内包表記内の処理から書き換えられるんですね。
guest

0

既に回答が出ているように、内包表記を使えば何でも速くなるわけではありません。
今回も内包表記の利用を検討する前に、もうちょっとできることがあったのでは。

Python

1from timeit import timeit 2 3def func1(): 4 count = 0 5 for i in range(10): 6 if i % 2 ==1: 7 for j in range(5): 8 if j % 2 ==1: 9 count += 1 10 11 return count 12 13def func2(): 14 count = 0 15 for i in range(1, 10, 2): 16 for j in range(1, 5, 2): 17 count += 1 18 19 return count 20 21 22print( 23 timeit(lambda: func1()), timeit(lambda: func2()) 24)

実行結果 Wandbox

5.155679266899824 2.9617500379681587

投稿2018/10/07 07:28

LouiS0616

総合スコア35658

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

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

opyon

2018/10/07 07:39

ありがとうございます。 >今回も内包表記の利用を検討する前に、もうちょっとできることがあったのでは。 仰る通りです。 分かりにくくて恐縮ですが、内包表記で書き直す練習をしていて処理が2つある場合に上手く書けずに質問用にサンプルコードを作ったのでこのコードを速くしようとしていた訳ではありません。 この質問とは本質的に別の話なので内包表記部分だけサンプルコードにして質問させて頂きました。 また、色々な方々からアドバイス頂き質問とは別のことでも参考になり感謝しています。
guest

0

内包表記では、for文と同じようには出来ないように思います。
次のように、二段階にして計算するのではダメでしょうか?
ループの処理が全て終わってから表示するのではなく、ループ処理の途中経過を表示したいのであれば、for文を使う方が良いかと思います。

temparr = [i for i in range(10) if i % 2 == 1] count = len(temparr) arr = [i*10 + j for i in temparr for j in range(5) if j % 2 == 1] print(*arr) print(count)

投稿2018/10/07 05:23

KNaito

総合スコア376

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

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

opyon

2018/10/07 05:37

ありがとうございます。 出来なそうな予感はしてましたがやはりそうですよね。 その根拠を探しているのですがなかなか見つかりません。
KNaito

2018/10/07 07:24

自分の理解では、外部変数のcountを更新出来ないことが原因のように思います。countを更新する代わりに、関数呼び出しや、オブジェクトのメソッド呼び出しを経由すれば、実装出来そうですが、、、。 あと、lambdaを使って一行で処理する方法も考えてみました。あまり綺麗なコードでないですが。 ``` (count, arr) = (lambda t : (len(t), [i*10 + j for i in t for j in range(5) if j % 2 == 1]))([i for i in range(10) if i % 2 == 1]) print(*arr) print(count) ```
opyon

2018/10/07 07:29

ありがとうございます。 他の方々からもご指摘あるように複雑な内包表記にはこだわらないという教訓を得ました。 お手数をお掛けしてすみません^^;
guest

0

Python

1count = 0 2for i in range(10): 3 if i % 2 ==1: 4 for j in range(5): 5 if j % 2 ==1: 6 count += 1 7 print(i*10 +j,end = ' ') 8print('count:',count) 9 10def f(i,j): 11 global count 12 if i % 2 == 1: 13 count += 1 14 return i*10 + j 15 16count = 0 17print(*[f(i,j) for i in range(10) if i % 2 == 1 for j in range(5) if j % 2 == 1],end = ' ') 18print('count:',count) 19
出力結果 11 13 31 33 51 53 71 73 91 93 count: 10 11 13 31 33 51 53 71 73 91 93 count: 10

投稿2018/10/07 06:01

opyon

総合スコア1009

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

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

opyon

2018/10/07 06:02

関数を作るくらいなら、複数行に分けたほうが素直ですよね。
tiitoi

2018/10/07 07:03

そうですね。 内包表記にすることによって、可読性が落ちるのであれば、使わないほうがいいかと思います。 重たい処理の高速化が主目的ならその部分だけC++で書いて、Python から呼び出したほうがよいので、Python なら 速度 <<<< 可読性重視でよいと思います。
opyon

2018/10/07 07:07

>重たい処理の高速化が主目的ならその部分だけC++で書いて、Python から呼び出したほうがよい Pythonって噂通り遅いようですね。速さを求めてはいけないと思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問