PythonにおけるRemove関数の使い方に基づいて議論する。

3180 ワード

先日プログラムを書いていますが、こんな問題がありました。
a=[a','b','c','d']
b=[c',d',e',f']
配列aの要素は、配列bに現れたものをすべて削除する必要があります。初めて書いたプログラムは以下の通りです。

a=['a','b','c','d']
b=['c','d','e','f']
for x in a:
 if x in b:
 a.remove(x)
print (a)
最後の出力結果は

このような結果が出た時、不思議に思いました。しかし、すぐに考えてみると、その原因がすぐに分かりました。
x='c'の場合、if条件文を満たし、if下の文を実行します。つまり'c'の要素をa配列から削除します。
削除後、remove関数は実行されませんでした。a配列のインデックス番号が削除要素インデックス番号より大きいすべての要素を順に前のビットに移動します。
このとき、xはa[2]を指し、a配列は現在の状態は「'a'、'b'、'd'」、a[2]には要素'd'として記憶されている。
remove関数が戻ったら、forループを続けて、xは配列の次のインデックスを指します。
したがって、「d」要素は配列bと比較されないことになる。
その後、次のようにプログラムを修正しました。

a=['a','b','c','d']
c=['a','b','c','d']
b=['c','d','e','f']
 
for x in a:
 if x in b:
 c.remove(x)
print (c)
プログラム運転の結果は以下の通りです。

問題はそんなに難しくないですが、この細部問題は必ず把握してください。
補足知識:Pythonリストのremove方法の注意事項

なぜリストのすべての要素が削除されませんでしたか?
説明:
実行順では、最初のスペースが削除されると、後ろの要素が前に移動します(「スペース」、「スペース」、「12」、「23」となります)。ポインタは次のときに新しいリストの2番目の要素(すなわち初期状態の3番目のスペース)を指します。初期状態の2番目の空格子がスキップされ、最初の3番目のスペースが削除され、次に後ろの要素が再び前に移動します。'12','23')は、新しいリストの3番目の要素、すなわち初期状態の5番目の要素23を指し、そして23は削除されたので、['スペース','12']だけが残ります。
初期リストの要素の一部を除外したいなら、どうやって実現しますか?
上記の状況では、リストを巡回しながら削除操作を実行すると、思いがけない結果となります。初期リストを巡回して、最初のリストのコピーを削除操作しますか?

以上の結果は、予期した効果が得られなかったことを示している。なぜですか?
copy=lsという文で問題がありますが、ここではcopyとlsが同じメモリを指しています。「新しいメモリを開発し、lsメモリの内容を新たなメモリにコピーし、Copyを新たに開発されたメモリ、すなわち深コピー、deep copy」という一連の操作を行っていません。したがって、copyに対して実行されるremove動作と、エルゴードのリストに対して、実質的には同じメモリに対して動作するので、結果は前の例と同様である。
この問題を解決するには、3つの方法があります。
(1)
ls='','''12','23','abc','aa'
copy='','''12','23','abc','aa'
この方法は既知のリストのすべての要素に対して、要素の数が少なく、構造が簡単な時に可能で、他の状況では不可能です。
(2)copyモジュールのdeepcopy方法を導入する:

Pythonリストのremove方法の注意事項
(3)もう一つの空のリストを用意し、初期リストを巡回すると、条件に該当する要素をそれぞれ空のリストに追加します。
この方法は考え方がremove法とは反対ですが、実行される操作はほぼ同じで、時間の複雑さもremove方法と同じです。copyモジュールを導入する必要はありません。
また、リストのremove方法については、python基礎教程の第二版で説明しています。
removeメソッドは、リスト内の値の最初のマッチ項目を削除します。

>>>x=['to','be','or','not','to','be']
>>>x.remove('be')
>>>x
['to','or','not','to','be']
以上は個人の経験ですので、参考にしていただければと思います。もし間違いがあったり、完全に考えていないところがあれば、コメント検討を歓迎します。