Pythonでリスト(配列)の要素を削除する方法【clear, pop, remove, del】
- 作成日: 2023-12-28
- 更新日: 2024-01-01
- カテゴリ: Python
Pythonでリスト(配列)の要素を削除するにはどうしたらいいでしょうか?
その場合はリストのメソッドであるclear
, pop
, remove
, そしてdel
文を使います。
またリスト内包表記を使うことでフィルタリングをすることもできます。
この記事ではこれらの使い方について解説していきます。
5. データ構造 — Python 3.12.1 ドキュメント
GitHub - python/cpython: The Python programming language
clear ... リスト内の要素をクリアする
list.clear()
はリストのメソッドで、リスト内の要素をすべて削除するメソッドです。
すべて削除することを「クリアする」と表現します。
l = [1, 2, 3]
print(l) # [1, 2, 3]
l.clear()
print(l) # []
このメソッドはpop()
を使った場合は以下と同じです。
l = [1, 2, 3]
while len(l):
l.pop(0)
print(l) # []
またdel l[:]
とも同じになります。
l = [1, 2, 3]
print(l) # [1, 2, 3]
del l[:]
print(l) # []
リスト内包表記を使った場合は以下と同じになります。
l = [1, 2, 3]
print(l) # [1, 2, 3]
l = [el for el in l if False]
print(l) # []
clear()のCPythonの実装
CPythonではリストのclear()
はcpython/Objects/clinic/listobject.c.h
のlist_clear()
関数が登録されています。
list_clear()
関数内ではcpython/Objects/listobject.c
のlist_clear_impl()
が呼び出されています。
list_clear_impl()
内ではさらに_list_clear()
関数が呼ばれており、clear()
の詳細な実装はこの_list_clear()
に実装されています。
_list_clear()
はint
型の整数0を返します。この値はlist_clear_impl()
内で無視されています。そしてlist_clear_impl()
はNone
を返します。
よってPythonのclear()
が返す値はNone
です。
l = [1, 2, 3]
print(l.clear()) # None
pop ... 末尾か、添え字の要素をポップする
このメソッドはリストの特定の添え字の要素をポップ(取り出して削除)するメソッドです。
引数には添え字を指定します。
l = [1, 2, 3]
print(l.pop(1)) # 2
print(l) # [1, 3]
print(l.pop(0)) # 1
print(l) # [3]
添え字が負数の場合は後方から参照されます。
l = [1, 2, 3]
print(l.pop(-1)) # 3
print(l) # [1, 2]
print(l.pop(-2)) # 1
print(l) # [2]
添え字がリストのサイズより大きい場合はIndexError
例外が送出されます。
l = [1, 2, 3]
try:
print(l.pop(100))
except IndexError as e:
print(e)
# pop index out of range
添え字を指定していない場合はリストの末尾の要素がポップされます。
リストが空の状態でpop()
した時はIndexError
例外が送出されます。
l = [1, 2, 3]
print(l.pop()) # 3
print(l.pop()) # 2
print(l.pop()) # 1
try:
print(l.pop())
except IndexError as e:
print(e)
# pop from empty list
このメソッドはdel
文の場合は以下のコードと同じです。
l = [1, 2, 3]
del l[1:2] # del 2
print(l) # [1, 3]
del l[0:1] # del 1
print(l) # [3]
リスト内包表記を使う場合は以下のコードと同じです。
l = [1, 2, 3]
l = [el for i, el in enumerate(l) if i != 1]
print(l) # [1, 3]
pop()のCPythonの実装
このメソッドはcpython/Objects/clinic/listobject.c.h
のlist_pop()
関数が登録されています。
list_pop()
内ではインデックスを引数から取り出して、cpython/Objects/listobject.c
のlist_pop_impl()
に処理を任せています。
list_pop_impl()
では実際に要素を削除する処理をしていますが、index
の添え字の値が負数の場合は単純にそのindex
にリストのサイズを加算しているだけです。
つまり加算してもリストのサイズに収まらない場合、以下のようなコードはエラーになります。
l = [1, 2, 3]
print(len(l)) # 3
try:
l.pop(-6)
except IndexError as e:
print(e)
# pop index out of range
上記のコードではl
は長さが3のリストです。pop()
の添え字は-6
なので-6 + 3
で加算結果は-3
になります。
-3
はリストの添え字の範囲外になるのでエラーになります。
pop()
の実装ですが、要素が取り出された後の残りの要素の配列内での移動はC言語のmemmove()
関数を使っています。
関連記事
C言語の配列を簡単にコピーする方法
リストの実装は配列になってますが、この配列の複数の要素をmemmove()
でずりっとずらしているだけです。単純な実装ですね。
pop()
はリストのリサイズに失敗した場合はポップ前のリストの状態を復元するようになってます。
リストのリサイズはlist_resize()
関数で行っていますが、内部ではPyMem_Realloc()
関数を使っています。
この関数はC言語のrealloc()
関数を呼び出す関数で、realloc()
はすでに確保されている動的メモリを伸縮する関数です。
C言語の動的配列の実装ではrealloc()
で配列を伸縮することがよく行われます。
関連記事
C言語の動的配列のリサイズ方法
remove ... 引数の値の要素を削除する
remove()
は引数の値を持つリスト内の要素を削除するメソッドです。
要素が見つからなかった場合はValueError
を送出します。
l = [10, 20, 30, 20]
print(l.remove(20)) # None
print(l) # [10, 30]
try:
l.remove(100)
except ValueError as e:
print(e)
# list.remove(x): x not in list
リストの先頭から走査して最初に見つけた値の要素を削除しています。
特定の値の要素をすべて削除したい場合はリスト内包表記を使って以下のようなコードを書きます。
l = [10, 20, 30, 20]
l = [el for el in l if el != 20]
print(l) # [10, 30]
あるいはfilter()
を使っても以下のように書けます。
l = [10, 20, 30, 20]
l = list(filter(lambda x: x != 20, l))
print(l) # [10, 30]
removeのCPythonの実装
remove()
のCPythonでの実装はcpython/Objects/listobject.c
のlist_remove()
関数が登録されています。
この関数内ではlist_ass_slice()
というリストのスライスの処理で使われる関数が流用されています。
リストのremove()
とリストのスライス処理は友達ということになります。
この関数内ではfor文でリストの要素を先頭から参照していますが、カウント変数の型はPy_ssize_t
型になってます。
この型はCPytohn/PC/pyconfig.h
で定義されていて、プラットフォームごとに中身が変わります。
Windows64ビットの場合は__int64
になっており、これはMicrosoft C/C++が独自拡張した予約語で64ビット長の符号付き整数を表しています。
この型のバイト数は8バイトで、値の範囲は最小値-9,223,372,036,854,775,808から 最大値9,223,372,036,854,775,807になります。
Windows64ビット以外ではint
型になっています。
int
型のサイズは処理系によって変わりますが一般的な処理系では4バイトであることが多いみたいです。
値の範囲は最小値-2147483648から最大値2147483647、になります。
del ... 特定の要素を削除する
リストの特定の要素を削除するのにdel
文が使えます。
del
文はオブジェクトを削除する文です。
l = [1, 2, 3]
del l[0]
print(l) # [2, 3]
del l[1]
print(l) # [2]
del
文の対象をスライスにすると、特定の範囲の要素をまとめて削除できます。
l = [1, 2, 3, 4, 5]
del l[1:4]
print(l) # [1, 5]
全ての要素を削除するには以下のようにコードを書きます。
l = [1, 2, 3]
del l[:]
print(l) # []
del文のCPythonの実装
del
文はcpython/Python/compile.c
のcompiler_visit_stmt()
関数で実装されています。
Pythonでは文ごとに定数が振られていてdel
文にはDelete_kind
という定数が振られています。
C言語のswitch文で分岐してDelete_kind
だった場合はVISIT_SEQ()
というマクロ関数を呼び出しています。
このマクロ関数は内部で識別子をプリプロセッサ時に連結し、compiler_visit_
で始まる関数を呼び分けています。
リスト内包表記 ... if文でフィルタリングする
リスト内包表記を使うと特定の要素を残して残りを削除することができます。
たとえば特定の要素を残したい場合は以下のようなコードを書きます。
l = [1, 2, 3, 2]
l = [el for el in l if el == 2] # 2だけ残す
print(l) # [2, 2]
特定の要素以外を残したい場合は以下のようなコードを書きます。
l = [1, 2, 3, 2]
l = [el for el in l if el != 2] # 2以外を残す
print(l) # [1, 3]
このようなフィルタリング処理はfilter()
を使っても行えます。
先ほどのコードは以下のコードと同じです。
l = [1, 2, 3, 2]
l = list(filter(lambda el: el == 2, l)) # 2だけ残す
print(l) # [2, 2]
l = [1, 2, 3, 2]
l = list(filter(lambda el: el != 2, l)) # 2以外を残す
print(l) # [1, 3]