- Python
Pythonリストの要素削除|remove・pop・del・clearの違い
Pythonのリストから要素を削除する方法は、値で消す remove()、位置で消して値を受け取る pop()、位置や範囲で消す del、すべて消す clear() の4つです。 「何を手がかりに消すか」と「消した値をあとで使うか」で選び分けます。
この記事では、4つの違いを指定方法・戻り値・存在しないときのエラー・複数削除の可否で比べる表を冒頭に置き、ValueErrorとIndexErrorを実際に出して確かめます。さらに、for文の中でremoveして要素が飛ばされる動きを1周ずつ表示して再現し、内包表記・スライス代入・逆順ループの3つの正解コードと、順序を保った重複削除も載せました。コードと出力は Python 3.11.15 で実行して確認したものです。
remove・pop・del・clearの比較表
| 比べる点 | remove(値) |
pop(位置) |
del リスト[位置] |
clear() |
|---|---|---|---|---|
| 指定方法 | 値 | インデックス(省略すると末尾) | インデックスまたはスライス | 指定なし |
| 消える要素 | 最初に見つかった1個 | 指定した位置の1個 | 指定した位置・範囲 | すべて |
| 戻り値 | None |
削除した要素 | なし(文なので値を返さない) | None |
| 存在しないとき | ValueError |
IndexError |
IndexError(スライスは範囲外でもエラーなし) |
エラーなし |
| 複数削除 | 1回の呼び出しで1個 | 1回の呼び出しで1個 | スライスで複数可 | 全要素 |
| 書き方の例 | a.remove("b") |
x = a.pop(0) |
del a[1:3] |
a.clear() |
やりたいことから引く場合は、次の表が便利です。
| やりたいこと | 書き方 |
|---|---|
| 値を指定して1個消す | a.remove("b") |
| 末尾を取り出して消す | x = a.pop() |
| 先頭を取り出して消す | x = a.pop(0) |
| 位置を指定して消す(値は不要) | del a[1] |
| 範囲をまとめて消す | del a[1:3] |
| すべて消す | a.clear() |
| 条件に合う要素をすべて消す | a = [x for x in a if 条件に合わない] |
| 同じ値をすべて消す | a = [x for x in a if x != 値] |
| 重複を消す(順序を保つ) | a = list(dict.fromkeys(a)) |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Pythonリストの要素削除|remove・pop・del・clearの違い」
4つの方法を実行結果で確かめる
remove:値を指定して最初の1個を消す
リスト.remove(値) は、先頭から探して最初に見つかった1個を削除します。同じ値が複数あっても、消えるのは1個だけです。
a = ["a", "b", "c", "b"]
result = a.remove("b")
print(a) # 最初の "b" だけが消える
print(result) # 戻り値は None
実行結果:
['a', 'c', 'b']
None
戻り値は None です。a = a.remove("b") と書くと、変数 a が None に置き換わってしまうので、removeは代入せずに単独の行で書きます。
pop:位置を指定して消し、その値を受け取る
リスト.pop(インデックス) は、指定した位置の要素を削除して、その要素を戻り値として返します。 インデックスを省略すると末尾の要素が対象です。
a = ["a", "b", "c", "d"]
last = a.pop() # 末尾
print(last, a)
first = a.pop(0) # 先頭
print(first, a)
second_last = a.pop(-2) # 負のインデックスも使える(後ろから2番目)
print(second_last, a)
実行結果:
d ['a', 'b', 'c']
a ['b', 'c']
b ['c']
「消した値をそのあとの処理で使う」ならpopが合っています。末尾から取り出していく動きは、後入れ先出し(スタック)の処理にそのまま使えます。
del:位置・範囲を指定して消す
del リスト[インデックス] は位置を指定して削除する文です。メソッドではないので値を返しません。スライスを使うと、範囲をまとめて削除できます。
a = ["a", "b", "c", "d", "e", "f", "g"]
del a[1] # 位置1
print(a)
del a[1:3] # 位置1〜2(終わりの位置3は含まない)
print(a)
del a[-1] # 末尾
print(a)
b = [0, 1, 2, 3, 4, 5, 6]
del b[::2] # 1つおき(偶数番目)を削除
print(b)
c = [0, 1, 2, 3, 4]
del c[:2] # 先頭から2個
print(c)
実行結果:
['a', 'c', 'd', 'e', 'f', 'g']
['a', 'e', 'f', 'g']
['a', 'e', 'f']
[1, 3, 5]
[2, 3, 4]
clear:すべての要素を消す
リスト.clear() はリストを空にします。Python公式チュートリアルでは、del a[:] と同じ動きとして説明されています。
a = ["a", "b", "c"]
result = a.clear()
print(a, result)
b = [1, 2, 3]
del b[:]
print(b)
実行結果:
[] None
[]
存在しない要素を消そうとしたときのエラー
4つの方法は、対象が見つからないときの動きが異なります。実際に実行してエラー文を確かめます。
removeはValueError
リストにない値を remove() に渡すと、ValueErrorになります。
a = ["a", "b", "c"]
a.remove("z")
実行結果:
Traceback (most recent call last):
File "sample.py", line 2, in <module>
a.remove("z")
ValueError: list.remove(x): x not in list
list.remove(x): x not in list は、「removeに渡した値がリストの中にない」 という意味です。
popとdelはIndexError
範囲外の位置を指定すると、IndexErrorになります。空のリストに対する pop() も同じです。
a = ["a", "b", "c"]
a.pop(10)
実行結果:
Traceback (most recent call last):
File "sample.py", line 2, in <module>
a.pop(10)
IndexError: pop index out of range
a = []
a.pop()
実行結果:
Traceback (most recent call last):
File "sample.py", line 2, in <module>
a.pop()
IndexError: pop from empty list
a = ["a", "b", "c"]
del a[10]
実行結果:
Traceback (most recent call last):
File "sample.py", line 2, in <module>
del a[10]
~^^^^
IndexError: list assignment index out of range
del のエラー文は list assignment index out of range です。「assignment(代入)」という言葉が入っていますが、削除でも同じ文が表示されます。
一方、スライスで範囲を指定した del は、範囲がリストの外にあってもエラーになりません。 該当する要素がなければ、何も削除されないだけです。
a = ["a", "b", "c"]
del a[5:9] # 範囲外のスライス
print(a)
del a[1:100] # 終わりがはみ出していても、ある分だけ消える
print(a)
実行結果:
['a', 'b', 'c']
['a']
popに値を渡すとTypeError
pop() の引数は位置(整数)です。removeのつもりで値を渡すと、TypeErrorになります。
a = ["a", "b", "c"]
a.pop("a")
実行結果:
Traceback (most recent call last):
File "sample.py", line 2, in <module>
a.pop("a")
TypeError: 'str' object cannot be interpreted as an integer
| エラー文 | 起きる場面 | 見直すところ |
|---|---|---|
ValueError: list.remove(x): x not in list |
removeに渡した値がリストにない | 値のつづり・型(1 と "1" は別の値) |
IndexError: pop index out of range |
popの位置が範囲外 | len(a) と位置の関係 |
IndexError: pop from empty list |
空のリストにpop | 空かどうかの確認 |
IndexError: list assignment index out of range |
delの位置が範囲外 | len(a) と位置の関係 |
TypeError: 'str' object cannot be interpreted as an integer |
popに値(文字列)を渡した | 値で消すならremove |
エラーにならないように消す書き方
「あれば消す、なければ何もしない」という処理は、次のどちらかで書けます。
a = ["a", "b", "c"]
# 1) in で確かめてから消す
if "z" in a:
a.remove("z")
print(a)
# 2) try / except で受け止める
try:
a.remove("z")
except ValueError:
print("見つからなかったので、何もしません")
# 3) 空かどうかを確かめてから pop する
stack = []
item = stack.pop() if stack else None
print(item)
実行結果:
['a', 'b', 'c']
見つからなかったので、何もしません
None
| 書き方 | 向いている場面 |
|---|---|
if 値 in a: で確かめる |
見つからないことがよくある。読みやすさを優先したい |
try / except ValueError |
ほとんどの場合は見つかる。見つからないときだけ別の処理をしたい |
a.pop() if a else None |
空のリストでも止めずに進めたい |
for文の中でremoveすると要素が飛ばされる
動きを1周ずつ表示して再現する
リストから「偶数をすべて消したい」と考えて、for文の中でremoveを呼ぶコードを書いてみます。結果には偶数が残ります。 どの要素が調べられたかを、1周ずつ表示して確かめましょう。
nums = [1, 2, 2, 3, 4, 4, 5]
for i, n in enumerate(nums):
print(f"{i}周目: n={n} その時点のリスト={nums}")
if n % 2 == 0:
nums.remove(n)
print("結果:", nums)
実行結果:
0周目: n=1 その時点のリスト=[1, 2, 2, 3, 4, 4, 5]
1周目: n=2 その時点のリスト=[1, 2, 2, 3, 4, 4, 5]
2周目: n=3 その時点のリスト=[1, 2, 3, 4, 4, 5]
3周目: n=4 その時点のリスト=[1, 2, 3, 4, 4, 5]
4周目: n=5 その時点のリスト=[1, 2, 3, 4, 5]
結果: [1, 2, 3, 4, 5]
7個の要素があるのに、ループは5周で終わっています。そして、2個目の 2 と2個目の 4 は一度も調べられていません。
理由は、for文が「いま何番目を見ているか」という位置を内部で数えているためです。
| 周 | 見ている位置 | そのときのリスト | 起きること |
|---|---|---|---|
| 0 | 位置0 → 1 |
[1, 2, 2, 3, 4, 4, 5] |
奇数なので何もしない |
| 1 | 位置1 → 2 |
[1, 2, 2, 3, 4, 4, 5] |
削除。後ろの要素が1つずつ前に詰まる |
| 2 | 位置2 → 3 |
[1, 2, 3, 4, 4, 5] |
位置1に詰まってきた 2 は飛ばされる |
| 3 | 位置3 → 4 |
[1, 2, 3, 4, 4, 5] |
削除。また1つ詰まる |
| 4 | 位置4 → 5 |
[1, 2, 3, 4, 5] |
位置3に詰まってきた 4 は飛ばされる |
削除すると後ろの要素が前に詰まり、次の周では「詰まってきた要素」の1つ先を見ることになります。 そのため、削除した要素のすぐ後ろの要素が調べられません。
エラーが出ないまま結果だけが変わる点が、気づきにくいところです。偶数だけのリストで試すと、半分が残ります。
nums = [2, 4, 6, 8]
for n in nums:
if n % 2 == 0:
nums.remove(n)
print(nums)
実行結果:
[4, 8]
インデックスで回しながら del する書き方では、途中でリストが短くなるため、IndexErrorで止まります。
nums = [1, 2, 3, 4]
for i in range(len(nums)): # range(4) は最初に決まる
if nums[i] % 2 == 0:
del nums[i]
実行結果:
Traceback (most recent call last):
File "sample.py", line 4, in <module>
if nums[i] % 2 == 0:
~~~~^^^
IndexError: list index out of range
正解1:内包表記で「残す要素」を集めた新しいリストを作る
もっとも読みやすい直し方は、消す条件ではなく「残す条件」を書いて、新しいリストを作る方法です。
nums = [1, 2, 2, 3, 4, 4, 5]
nums = [n for n in nums if n % 2 != 0] # 奇数だけを残す
print(nums)
実行結果:
[1, 3, 5]
元のリストを順に読むだけで、読んでいる最中のリストは変更しないため、要素が飛ばされることがありません。条件で削除したいときは、まずこの書き方を選ぶとよいでしょう。
正解2:スライス代入で、同じリストの中身を入れ替える
正解1は「新しいリストを作って、変数に付け替える」動きです。同じリストを別の変数や関数の引数からも参照している場合、そちらには変更が伝わりません。同じリストのまま中身を入れ替えたいときは、左辺を nums[:] にします。
# 変数に付け替えた場合:別名からは元のまま見える
nums = [1, 2, 2, 3, 4, 4, 5]
alias = nums
nums = [n for n in nums if n % 2 != 0]
print(nums, alias, nums is alias)
# スライス代入の場合:同じリストの中身が入れ替わる
nums = [1, 2, 2, 3, 4, 4, 5]
alias = nums
nums[:] = [n for n in nums if n % 2 != 0]
print(nums, alias, nums is alias)
実行結果:
[1, 3, 5] [1, 2, 2, 3, 4, 4, 5] False
[1, 3, 5] [1, 3, 5] True
関数の中で、引数として受け取ったリストから要素を削除したいときに役立ちます。
def drop_even(values):
values[:] = [v for v in values if v % 2 != 0] # 呼び出し元のリストが変わる
data = [1, 2, 3, 4, 5, 6]
drop_even(data)
print(data)
実行結果:
[1, 3, 5]
正解3:逆順ループで後ろから消す
その場で1個ずつ消したいときは、後ろから前に向かって調べます。削除で詰まるのは「消した位置より後ろ」だけなので、これから調べる前側の位置はずれません。
nums = [1, 2, 2, 3, 4, 4, 5]
for i in range(len(nums) - 1, -1, -1): # 6, 5, 4, ..., 0
if nums[i] % 2 == 0:
del nums[i]
print(nums)
実行結果:
[1, 3, 5]
reversed(range(len(nums))) と書いても同じ順番になります。
このほかに、リストのコピー(nums[:])を回しながら、元のリストから消す書き方もあります。
nums = [1, 2, 2, 3, 4, 4, 5]
for n in nums[:]: # コピーを回す
if n % 2 == 0:
nums.remove(n) # 元のリストから消す
print(nums)
実行結果:
[1, 3, 5]
3つの正解の選び方
| 書き方 | 同じリストのまま変わるか | 向いている場面 |
|---|---|---|
内包表記 a = [x for x in a if ...] |
新しいリストになる | 条件で削除するときの基本形 |
スライス代入 a[:] = [x for x in a if ...] |
同じリストのまま | 引数で受け取ったリストや、別の変数からも参照しているリスト |
逆順ループ + del a[i] |
同じリストのまま | 削除と同時に、位置を使った別の処理もしたいとき |
コピーを回す for x in a[:]: |
同じリストのまま | 件数が少なく、元のfor文の形を保ちたいとき |
条件に合う要素をまとめて削除する
同じ値をすべて消す
remove() が消すのは最初の1個です。同じ値をすべて消すなら、内包表記で「その値ではない要素」を残します。
a = ["x", "y", "x", "z", "x"]
b = a.copy()
b.remove("x")
print(b) # 最初の1個だけ
print([v for v in a if v != "x"]) # すべて消す
c = a.copy()
while "x" in c: # while と remove の組み合わせでも書ける
c.remove("x")
print(c)
実行結果:
['y', 'x', 'z', 'x']
['y', 'z']
['y', 'z']
whileの書き方は、1回ごとにリストを先頭から探し直します。要素数が多い場合は内包表記のほうが処理が少なく済みます。
空文字・Noneを取り除く
a = ["a", "", None, "b", 0]
print([v for v in a if v]) # 空文字・None・0 など「偽」とみなされる値をすべて除く
print([v for v in a if v is not None]) # None だけを除く
print([v for v in a if v != ""]) # 空文字だけを除く
print(list(filter(None, a))) # 1行目と同じ結果
実行結果:
['a', 'b']
['a', '', 'b', 0]
['a', None, 'b', 0]
['a', 'b']
if v という条件は、0 や False も取り除きます。数値の0を残したいデータでは、is not None のように消したい値をはっきり書くと意図どおりになります。
複数の位置をまとめて消す
消したい位置が複数あるときは、大きい位置から順に消すか、内包表記で残す位置を選びます。小さい位置から消すと、後ろの位置が1つずつずれます。
# 位置0と位置3("a" と "d")を消したい
a = ["a", "b", "c", "d", "e"]
for i in [0, 3]: # 小さい順に消すと、ずれて "e" が消える
del a[i]
print(a)
a = ["a", "b", "c", "d", "e"]
for i in sorted([0, 3], reverse=True): # 大きい順に消す
del a[i]
print(a)
a = ["a", "b", "c", "d", "e"]
drop = {0, 3}
print([v for i, v in enumerate(a) if i not in drop]) # 残す位置を選ぶ
実行結果:
['b', 'c', 'd']
['b', 'c', 'e']
['b', 'c', 'e']
辞書のリストから条件で消す
tasks = [
{"id": 1, "title": "資料作成", "done": True},
{"id": 2, "title": "レビュー", "done": False},
{"id": 3, "title": "備品発注", "done": True},
]
tasks = [t for t in tasks if not t["done"]] # 完了したタスクを取り除く
print(tasks)
実行結果:
[{'id': 2, 'title': 'レビュー', 'done': False}]
スライスで消す・切り出す
スライスには、元のリストを変える書き方と、新しいリストを作る書き方があります。
a = ["a", "b", "c", "d", "e"]
print(a[1:]) # 先頭を除いた新しいリスト
print(a[:-1]) # 末尾を除いた新しいリスト
print(a) # 元のリストはそのまま
del a[1:3] # 元のリストから削除
print(a)
a[1:2] = [] # 空のリストを代入しても削除になる
print(a)
実行結果:
['b', 'c', 'd', 'e']
['a', 'b', 'c', 'd']
['a', 'b', 'c', 'd', 'e']
['a', 'd', 'e']
['a', 'e']
| 書き方 | 元のリスト | 結果 |
|---|---|---|
b = a[1:] |
変わらない | 先頭を除いた新しいリスト |
b = a[:-1] |
変わらない | 末尾を除いた新しいリスト |
del a[1:3] |
変わる | 位置1〜2を削除 |
a[1:3] = [] |
変わる | del a[1:3] と同じ |
del a[:n] |
変わる | 先頭からn個を削除 |
重複を削除する:順序を保つ書き方
重複を取り除く方法として set() がよく知られていますが、集合は順番を持たないため、元の並びが保たれるとは限りません。 順序を保ちたいときは dict.fromkeys() を使います。辞書のキーは重複せず、追加した順番が保たれる性質を利用しています。
a = [3, 1, 3, 2, 1, 5]
print(list(set(a))) # 重複は消えるが、並びは元と変わることがある
print(list(dict.fromkeys(a))) # 最初に出てきた順番を保つ
print(sorted(set(a))) # 並べ替えてよいなら sorted
# for 文で書く場合(何をしているかが追いやすい)
seen = set()
result = []
for v in a:
if v not in seen:
seen.add(v)
result.append(v)
print(result)
実行結果:
[1, 2, 3, 5]
[3, 1, 2, 5]
[1, 2, 3, 5]
[3, 1, 2, 5]
| 書き方 | 順序 | 条件 |
|---|---|---|
list(set(a)) |
保たれるとは限らない | 要素がハッシュ可能 |
list(dict.fromkeys(a)) |
最初に出てきた順 | 要素がハッシュ可能 |
sorted(set(a)) |
昇順に並べ替え | 要素がハッシュ可能で、大小を比べられる |
for文 + seen |
最初に出てきた順 | 判定に使うキーを自由に決められる |
ハッシュ可能とは、辞書のキーや集合の要素にできる値のことです。数値・文字列・タプルは該当し、リストや辞書は該当しません。
リストや辞書が要素のときの重複削除
要素がリストの場合、dict.fromkeys() はTypeErrorになります。この場合は、in で確かめながら追加するか、辞書の特定のキーを基準にします。
rows = [[1, 2], [1, 2], [3]]
try:
print(list(dict.fromkeys(rows)))
except TypeError as e:
print("TypeError:", e)
unique = []
for r in rows:
if r not in unique: # in で1つずつ比べる
unique.append(r)
print(unique)
# 辞書のリスト:id が同じものは最初の1件だけ残す
members = [{"id": 1, "name": "A"}, {"id": 2, "name": "B"}, {"id": 1, "name": "C"}]
seen = set()
result = []
for m in members:
if m["id"] not in seen:
seen.add(m["id"])
result.append(m)
print(result)
実行結果:
TypeError: unhashable type: 'list'
[[1, 2], [3]]
[{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}]
知っておくと役立つ補足
clear()と a = [] の違い
「空にする」書き方として a = [] もありますが、動きが異なります。clear() は同じリストを空にし、a = [] は変数を新しい空リストに付け替えます。
a = [1, 2, 3]
b = a # 同じリストを指す別名
a.clear()
print(a, b) # どちらも空
a = [1, 2, 3]
b = a
a = [] # a だけが新しいリストを指す
print(a, b) # b には元の中身が残る
実行結果:
[] []
[] [1, 2, 3]
| 書き方 | 同じリストを指す別の変数 |
|---|---|
a.clear() / del a[:] |
一緒に空になる |
a = [] |
元の中身が残る |
del a は変数そのものを削除する
del a[:] は中身を消しますが、del a は変数名そのものを削除します。 そのあとで a を使うとNameErrorになります。
a = [1, 2, 3]
del a
print(a)
実行結果:
Traceback (most recent call last):
File "sample.py", line 3, in <module>
print(a)
^
NameError: name 'a' is not defined
値の位置を調べてから消す:index
「値で探して、位置で消す」ときは index() と組み合わせます。見つかった位置を別の処理にも使いたい場合に便利です。
a = ["a", "b", "c"]
i = a.index("b") # 値の位置を調べる(見つからないと ValueError)
print(i)
del a[i]
print(a)
実行結果:
1
['a', 'c']
removeは「==」で等しい要素を探す
remove() は、渡した値と == で等しい最初の要素を削除します。型が違っても等しいと判定される値(1 と 1.0 と True)は同じものとして扱われ、数値の 1 と文字列の "1" は別の値として扱われます。
a = [1.0, 1, True]
a.remove(True) # True == 1.0 が成り立つので、先頭の 1.0 が消える
print(a)
b = ["1", "2", "3"] # 文字列のリスト
try:
b.remove(1) # 数値の 1 は見つからない
except ValueError as e:
print("ValueError:", e)
b.remove("1")
print(b)
実行結果:
[1, True]
ValueError: list.remove(x): x not in list
['2', '3']
ファイルや入力から読み込んだ値は文字列になっていることが多いので、ValueErrorが出たときは print(repr(値)) で型を確かめると原因を見つけやすくなります。
条件に合う要素を、別のリストに移す
「消す」だけでなく「取り除いた要素も使いたい」ときは、残すリストと移すリストを内包表記で1つずつ作ります。
orders = [120, 980, 45, 300, 1500]
large = [v for v in orders if v >= 300] # 移す側
orders = [v for v in orders if v < 300] # 残す側
print(orders)
print(large)
実行結果:
[120, 45]
[980, 300, 1500]
2次元リスト(入れ子のリスト)から消す
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
del m[0][1] # 0行目の位置1
print(m)
m = [row for row in m if row[0] != 4] # 条件に合う行を取り除く
print(m)
m = [row[1:] for row in m] # すべての行から先頭の列を取り除く
print(m)
実行結果:
[[1, 3], [4, 5, 6], [7, 8, 9]]
[[1, 3], [7, 8, 9]]
[[3], [8, 9]]
先頭から何度も取り出すならdeque
pop(0) は、先頭を消すたびに残りの要素を1つずつ前へ詰めます。要素数が多いリストの先頭から何度も取り出す処理では、標準ライブラリの collections.deque の popleft() が向いています。
import timeit
from collections import deque
q = deque([1, 2, 3])
print(q.popleft(), q)
n = 100000
t_end = timeit.timeit("a.pop()", "a = list(range(200000))", number=n)
t_head = timeit.timeit("a.pop(0)", "a = list(range(200000))", number=n)
t_deque = timeit.timeit("a.popleft()", "from collections import deque; a = deque(range(200000))", number=n)
print(f"list.pop() : {t_end:.4f} 秒")
print(f"list.pop(0) : {t_head:.4f} 秒")
print(f"deque.popleft() : {t_deque:.4f} 秒")
実行結果(時間は環境と実行のたびに変わります。この環境での一例です):
1 deque([2, 3])
list.pop() : 0.0021 秒
list.pop(0) : 2.8437 秒
deque.popleft() : 0.0019 秒
20万個の要素から10万回取り出す計測では、pop(0) だけ時間が大きくなりました。数十〜数百個程度のリストなら pop(0) で十分です。
タプルと文字列は削除できない
タプルと文字列は、作ったあとに変更できない型です。removeやdelは使えないので、リストに変換するか、条件で選び直して新しい値を作ります。
t = (1, 2, 3)
try:
t.remove(2)
except AttributeError as e:
print("AttributeError:", e)
print(tuple(v for v in t if v != 2)) # 条件で選び直して新しいタプルを作る
実行結果:
AttributeError: 'tuple' object has no attribute 'remove'
(1, 3)
どれを使うかの判断表
| 状況 | 選ぶもの |
|---|---|
| 値がわかっていて、1個消したい | remove(値) |
| 位置がわかっていて、消した値を使いたい | pop(位置) |
| 位置がわかっていて、値は不要 | del a[位置] |
| 範囲をまとめて消したい | del a[開始:終了] |
| すべて消したい(同じリストのまま) | clear() |
| 条件に合う要素をすべて消したい | 内包表記(同じリストのままならスライス代入) |
| ループしながら消したい | 逆順ループ、またはコピーを回す |
| 重複を消したい(順序を保つ) | list(dict.fromkeys(a)) |
| 先頭から何度も取り出したい | collections.deque の popleft() |
よくある質問
Q. removeとpopとdelはどう使い分けますか?
A. 値で消すなら remove、位置で消して値を受け取るなら pop、位置や範囲で消すだけなら del です。removeが消すのは最初に見つかった1個で、範囲をまとめて消せるのはdelのスライス指定です。
Q. for文の中でremoveすると、消えない要素があるのはなぜですか? A. 削除すると後ろの要素が前に詰まり、次の周ではその1つ先を見るため、削除した要素の直後が調べられないからです。内包表記で残す要素を集める、スライス代入にする、逆順で回す、のいずれかで直せます。
Q. 条件に合う要素をすべて削除するには?
A. a = [x for x in a if 残したい条件] と内包表記で書くのが基本です。関数の引数など、同じリストのまま中身を変えたい場合は a[:] = [...] とスライス代入にします。
Q. 重複を削除すると順番が変わります。
A. set() は順番を持たないためです。list(dict.fromkeys(a)) を使うと、最初に出てきた順番を保ったまま重複を取り除けます。
まとめ
- 値で消すなら
remove、位置で消して値を使うならpop、位置・範囲で消すならdel、すべて消すならclear - 戻り値があるのは
popだけ。removeとclearはNoneを返すので、代入せずに単独で書く - 見つからないとき、
removeは ValueError、popとdelは IndexError。スライスのdelは範囲外でもエラーにならない - for文の中でremoveすると、削除した直後の要素が飛ばされる。エラーが出ないまま結果が変わる
- 直し方は内包表記・スライス代入・逆順ループの3つ。迷ったら内包表記で「残す条件」を書く
- 順序を保った重複削除は
list(dict.fromkeys(a))。要素がリストや辞書のときはfor文で書く clear()は同じリストを空にし、a = []は変数を付け替える。別の変数から参照しているときに違いが出る
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Pythonリストの要素削除|remove・pop・del・clearの違い」
株式会社RJCでは、Pythonのリスト操作を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。