1つのステートメントでPythonリストから複数のアイテムを削除する


107

Pythonでは、リストから項目を削除する方法を知っています。

item_list = ['item', 5, 'foo', 3.14, True]
item_list.remove('item')
item_list.remove(5)

上記のコードは、item_listから値5と 'item'を削除します。しかし、削除するものがたくさんある場合、私は多くの行を書かなければなりません

item_list.remove("something_to_remove")

削除するもののインデックスがわかっている場合は、次を使用します。

del item_list[x]

ここで、xは削除するアイテムのインデックスです。

削除するすべての数値のインデックスがわかっている場合は、インデックスにdelあるアイテムに対して何らかのループを使用します。

しかし、削除したいアイテムのインデックスがわからない場合はどうなりますか?

を試しましたがitem_list.remove('item', 'foo')remove引数が1つしかとらないというエラーが表示されました。

1つのステートメントでリストから複数のアイテムを削除する方法はありますか?

私が使用したPS delremove。誰かがこれら2つの違いを説明できますか、それとも同じですか?

ありがとう


1
2番目の質問に答えるにはdel、インデックスでアイテムを削除します。removeリストの関数は、アイテムのインデックスを見つけて、delそのインデックスを呼び出します。
アーロンクリスチャンセン

回答:


159

Pythonでは、新しいオブジェクトを作成する方が既存のオブジェクトを変更するよりも優れていることがよくあります。

item_list = ['item', 5, 'foo', 3.14, True]
item_list = [e for e in item_list if e not in ('item', 5)]

これは次と同等です:

item_list = ['item', 5, 'foo', 3.14, True]
new_list = []
for e in item_list:
    if e not in ('item', 5):
        new_list.append(e)
item_list = new_list

フィルター処理された値の大きなリスト(ここで('item', 5)は、要素の小さなセットです)の場合setin操作がO(1)にあるため、a を使用するとパフォーマンスが向上します。

item_list = [e for e in item_list if e not in {'item', 5}]

コメントで説明さここで提案されているように、次のようにすると、各ループでセットが作成されるのを回避して、さらに時間を節約できる可能性があります。

unwanted = {'item', 5}
item_list = [e for e in item_list if e not in unwanted]

ブルームフィルタは、メモリが安くはない場合にも優れたソリューションです。


私は最初の答えが好きです。私は新しいリストを作っているわけではありません。ありがとう!
RandomCoder 2016年

セットはpython 2で最適化されていますか、それともpython 3でのみ最適化されていますか?つまり、バイトコードが生成されるときにセットが一度だけ作成されるのですか?
Har

セットは、定義によりin操作用に最適化されています。4つのプリミティブデータ構造の比較については、このベンチマークを参照してください。はい、ここで提案されているように、セットは各ループで構築されます。その結果、セットを専用の変数に保存してジェネレータ式で使用すると、時間を節約できます。
aluriak

@RandomCoder実際に新しいリストを作成し、名前を再利用します。これをid(item_list)前後で比較することで確認できitem_list = [e for e in item_list if e not in ('item', 5)]ます。回答をチェックして、リストを適切に変更する方法を確認してください。
Darkonaut

20
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove=['item', 5, 'foo']

削除後の最終的なリストは次のようになります

final_list=[3.14, True]

単一行コード

final_list= list(set(item_list).difference(set(list_to_remove)))

出力は次のようになります

final_list=[3.14, True]

13
いいえ、リストのアイテムをシャッフルします。アイテムの順序が重要ではない場合にのみ使用してください。
スカベンジャー

5
これにより、リストから重複も削除されます。ただし、リストの例では重要ではありません
tschale

1
この答えは正しくなく、深刻なバグを引き起こす可能性があります。なぜそれが支持されているのですか?
omerfarukdogan

1
重複を削除します!答えは深刻なバグを引き起こす可能性があるので、使用しないでください。
user2698178

2

誰もがsetpython のsの驚くべき機能に言及し忘れた理由がわかりません。リストをセットにキャストして、次のような単純な式で削除するものをすべて削除できます。

>>> item_list = ['item', 5, 'foo', 3.14, True]
>>> item_list = set(item_list) - {'item', 5}
>>> item_list
{True, 3.14, 'foo'}
>>> # you can cast it again in a list-from like so
>>> item_list = list(item_list)
>>> item_list
[True, 3.14, 'foo']

6
ただし、オブジェクトの順序は維持されません。
Astrid

また、リストに存在する可能性のある重複を削除します。
kyriakosSt

1

ここにも収まるので、ここから回答を再投稿しています。複数の値を削除するか、これらの値の重複のみを削除して、新しいリストを返すか、所定のリストを変更します。


def removed(items, original_list, only_duplicates=False, inplace=False):
    """By default removes given items from original_list and returns
    a new list. Optionally only removes duplicates of `items` or modifies
    given list in place.
    """
    if not hasattr(items, '__iter__') or isinstance(items, str):
        items = [items]

    if only_duplicates:
        result = []
        for item in original_list:
            if item not in items or item not in result:
                result.append(item)
    else:
        result = [item for item in original_list if item not in items]

    if inplace:
        original_list[:] = result
    else:
        return result

Docstring拡張:

"""
Examples:
---------

    >>>li1 = [1, 2, 3, 4, 4, 5, 5]
    >>>removed(4, li1)
       [1, 2, 3, 5, 5]
    >>>removed((4,5), li1)
       [1, 2, 3]
    >>>removed((4,5), li1, only_duplicates=True)
       [1, 2, 3, 4, 5]

    # remove all duplicates by passing original_list also to `items`.:
    >>>removed(li1, li1, only_duplicates=True)
      [1, 2, 3, 4, 5]

    # inplace:
    >>>removed((4,5), li1, only_duplicates=True, inplace=True)
    >>>li1
        [1, 2, 3, 4, 5]

    >>>li2 =['abc', 'def', 'def', 'ghi', 'ghi']
    >>>removed(('def', 'ghi'), li2, only_duplicates=True, inplace=True)
    >>>li2
        ['abc', 'def', 'ghi']
"""

本当に何をしたいかを明確にし、既存のリストを変更するか、特定のアイテムが欠落している新しいリストを作成する必要があります。既存のリストを指す2番目の参照がある場合に備えて、その区別を付けることが重要です。あなたが持っている場合、例えば...

li1 = [1, 2, 3, 4, 4, 5, 5]
li2 = li1
# then rebind li1 to the new list without the value 4
li1 = removed(4, li1)
# you end up with two separate lists where li2 is still pointing to the 
# original
li2
# [1, 2, 3, 4, 4, 5, 5]
li1
# [1, 2, 3, 5, 5]

これは、希望する動作である場合とそうでない場合があります。


1

あなたは使用することができますfilterfalseから機能をitertoolsモジュール

import random
from itertools import filterfalse

random.seed(42)

data = [random.randrange(5) for _ in range(10)]
clean = [*filterfalse(lambda i: i == 0, data)]
print(f"Remove 0s\n{data=}\n{clean=}\n")


clean = [*filterfalse(lambda i: i in (0, 1), data)]
print(f"Remove 0s and 1s\n{data=}\n{clean=}")

出力:

Remove 0s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 1, 1, 1, 4, 4]

Remove 0s and 1s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 4, 4]

0

しかし、削除したいアイテムのインデックスがわからない場合はどうなりますか?

.removeが嫌いな理由はよくわかりませんが、値に対応する最初のインデックスを取得するには、.index(value)を使用します。

ind=item_list.index('item')

次に、対応する値を削除します。

del item_list.pop[ind]

.index(value)は最初に出現するvalueを取得し、.remove(value)は最初に出現するvalueを削除します


結果の値が必要ない場合は、のdel item_list[ind]代わりに使用することを検討してくださいpop
kojiro

-1

あなたはこれを使うことができます-

リストがあるとしましょう。 l = [1,2,3,4,5]

1つのステートメントで最後の2つのアイテムを削除したい

del l[3:]

出力があります:

l = [1,2,3]

単純にする

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.