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

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

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

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

Q&A

解決済

2回答

1159閲覧

if or文が機能しない

Sigma1630

総合スコア36

Python 3.x

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

0グッド

0クリップ

投稿2018/06/01 13:50

ごくごく簡単なif or 文に基づき、リストの要素を選定したいのですが、
なぜか動いてくれません。

【書いたコード】

python

1ls = [[2, 0], [2, -1], [4, 0], [2, 1], [1, 0]] 2for i in ls: 3 if i[0] < 0 or i[0] >= 3 or i[1] < 0 or i[1] >= 5: 4 ls.remove(i) 5 6print(ls)

【期待する出力】

python

1[[2, 0], [2, 1], [1, 0]] #if文により[2,-1]と[4,0]に消えてほしい

【実際の出力】

python

1[[2, 0], [4, 0], [2, 1], [1, 0]]

[4,0]が消えません。
何か演算子を間違えてるとか、スペースとかの問題だったりするんでしょうか。
色々ネットでif or文を調べたり、orを使わずに全部ifの入れ子にしてみたりしましたがダメでした。

すみませんがご教示いただければ助かります。

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

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

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

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

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

guest

回答2

0

ベストアンサー

巡回中のリストに要素を追加したり、削除したりしてはいけません。
次のように浅いコピーを取るのが簡単です。

Python

1ls = [[2, 0], [2, -1], [4, 0], [2, 1], [1, 0]] 2for i in ls[:]: 3 if i[0] < 0 or i[0] >= 3 or i[1] < 0 or i[1] >= 5: 4 ls.remove(i) 5 6print(ls)

実行結果 Wandbox

[[2, 0], [2, 1], [1, 0]]

元のコードがうまくいかない理由

実際に試してみると面白いです。

Python

1# 2lst = [1, 2, 3, 4, 5] 3for elem in lst: 4 print(elem) 5 lst.remove(elem) 6 7print(lst) 8 9# 10lst = [1, 2, 3, 4, 5] 11for elem in lst[:]: 12 print(elem) 13 lst.remove(elem) 14 15print(lst)

実行結果 Wandbox

1 3 5 [2, 4] 1 2 3 4 5 []

ただし

今回は『排除する条件』より『排除しない条件』の方が書きやすそうです。
ついでにリスト内包表記も利用してみます。

Python

1ls = [[2, 0], [2, -1], [4, 0], [2, 1], [1, 0]] 2ls = [ 3 row for row in ls 4 if 0 <= row[0] < 3 5 if 0 <= row[1] < 5 6] 7 8print(ls)

Wandbox

投稿2018/06/01 14:02

編集2018/06/01 14:11
LouiS0616

総合スコア35660

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

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

Sigma1630

2018/06/01 14:07

LouiS0616さん、いつも早急にご回答いただきありがとうございます。 浅いコピーを参照先にして、そこでひっかかった要素をコピー元のlsから抜く感じですね。 [:]が浅いコピーになるのは知りませんでした。 元のやり方でできない理由がちょっとわからないですが、参考になりました、ありがとうございます。
LouiS0616

2018/06/01 14:11

> 元のやり方でできない理由がちょっとわからない 追記しておきました。
Sigma1630

2018/06/01 14:18

あー!わかりました。ls[0],ls[1],ls[2]…って順番に消していくと頭から消した場合結果的に1個飛ばしになってしまう感じですね!ありがとうございます。内包表記もそろそろ覚えます。
guest

0

for文で回しているリストを直接操作すると、理解しがたい現象が起こります。

python

1ls = [[2, 0], [2, -1], [4, 0], [2, 1], [1, 0]] 2for i in ls: 3 print(i) 4 if i[0] < 0 or i[0] >= 3 or i[1] < 0 or i[1] >= 5: 5 ls.remove(i) 6 7print(ls) 8""" => 9[2, 0] 10[2, -1] 11[2, 1] 12[1, 0] 13[[2, 0], [4, 0], [2, 1], [1, 0]] 14"""

これは仕様なので(ドキュメントに書いてあるのかしら・・・)、このままのコードで行くのは無理です。

回避策は、

python

1ls = [[2, 0], [2, -1], [4, 0], [2, 1], [1, 0]] 2for i in ls[:]: # 範囲指定なしのスライスでリストのコピーが作れる。本体とは違うリストを回す 3 if i[0] < 0 or i[0] >= 3 or i[1] < 0 or i[1] >= 5: 4 ls.remove(i) 5 6print(ls)

とか

python

1ls = [[2, 0], [2, -1], [4, 0], [2, 1], [1, 0]] 2ls = [i 3 for i in ls 4 if not (i[0] < 0 or i[0] >= 3 or i[1] < 0 or i[1] >= 5)] # 内包表記で元のリストは変更せず操作し、作ってから最後に再代入する 5print(ls)

とかがあります。

追記

この話はドキュメントにありました。まあ説明になっているようななっていないような微妙な感じですが。

8. 複合文 (compound statement) — Python 3.6.5 ドキュメント

投稿2018/06/01 14:07

編集2018/06/01 14:09
hayataka2049

総合スコア30933

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

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

Sigma1630

2018/06/01 14:53

hayataka2049様 ありがとうございます。リスト操作でこういうエラーを起こしやすいことを考えると、pythonの場合は内包表記に慣れたほうがよいかもと思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問