1. ホーム
  2. パイソン

[解決済み】リスト内の項目が存在する場合、それを削除する方法は?

2022-03-26 20:53:43

質問

私は new_tag を持つフォームのテキストフィールドから self.response.get("new_tag")selected_tags というチェックボックスフィールドから

self.response.get_all("selected_tags")

このように組み合わせています。

tag_string = new_tag
new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)

( f1.striplist はリスト内の文字列の中の空白を取り除く関数です)。

しかし、その場合 tag_list は空だが(新しいタグが入力されていない)、いくつかの selected_tags , new_tag_list は空の文字列を含んでいます " " .

例えば logging.info :

new_tag
selected_tags[u'Hello', u'Cool', u'Glam']
new_tag_list[u'', u'Hello', u'Cool', u'Glam']

空文字列を取り除くにはどうしたらいいですか?

リストの中に空の文字列がある場合。

>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> i = s.index("")
>>> del s[i]
>>> s
[u'Hello', u'Cool', u'Glam']

しかし、空文字列がない場合は

>>> s = [u'Hello', u'Cool', u'Glam']
>>> if s.index(""):
        i = s.index("")
        del s[i]
    else:
        print "new_tag_list has no empty string"

しかし、これは与える。

Traceback (most recent call last):
  File "<pyshell#30>", line 1, in <module>
    if new_tag_list.index(""):
        ValueError: list.index(x): x not in list

なぜこのような現象が起こるのか、また、どのように回避すればよいのか。

解決方法は?

1)ほぼ英文スタイル。

を使用して存在感をテストします。 in 演算子を適用し、さらに remove メソッドを使用します。

if thing in some_list: some_list.remove(thing)

remove メソッドは、最初に出現した thing すべての出現回数を削除するには while の代わりに if .

while thing in some_list: some_list.remove(thing)    

  • シンプルで、小さなリストには最適です。

2) ダックタイピング , EAFP のスタイルになります。

Pythonでは、このような「先手必勝」「後手必問」の姿勢が一般的です。オブジェクトが適切かどうかを事前にテストする代わりに、ただ操作を実行し、関連する例外をキャッチします。

try:
    some_list.remove(thing)
except ValueError:
    pass # or scream: thing not in some_list!
except AttributeError:
    call_security("some_list not quacking like a list!")

もちろん、上の例の2番目のexcept節は、ユーモアに欠けるだけでなく、全く不要である(ポイントは、この概念をよく知らない人のためにダックタイピングを説明することであった)。

複数回のthingの出現が予想される場合。

while True:
    try:
        some_list.remove(thing)
    except ValueError:
        break

  • この特定の使用例では少し冗長ですが、Pythonでは非常にイディオムです。
  • これは#1よりも性能が良い
  • PEP 463 は、ここで便利な try/except の単純な使用法のための短い構文を提案しましたが、承認されませんでした。

しかし contextlib の suppress() コンテキストマネージャである (python 3.4で導入)上記のコードは次のように簡略化できます。

with suppress(ValueError, AttributeError):
    some_list.remove(thing)

繰り返しになりますが、thingの複数回出現が予想される場合。

with suppress(ValueError):
    while True:
        some_list.remove(thing)

3)機能的なスタイル

1993年頃、Pythonは lambda , reduce() , filter()map() を提供します。 Lisp ハッカーがそれを見逃して、動作するパッチを提出しました*。また filter を使えば、リストから要素を削除することができます。

is_not_thing = lambda x: x is not thing
cleaned_list = filter(is_not_thing, some_list)

あなたのケースに役立つショートカットがあります:空のアイテム(実際には bool(item) == False のように None ゼロ、空文字列、その他の空のコレクション)、最初の引数としてNoneを渡すことができます。

cleaned_list = filter(None, some_list)

  • [更新]をクリックします。 : Python 2.x では。 filter(function, iterable) と等価であった。 [item for item in iterable if function(item)] (または [item for item in iterable if item] は、最初の引数が None ); Python 3.xでは、これと同等になりました。 (item for item in iterable if function(item)) . 微妙な違いは、以前は filter がリストを返していましたが、現在はジェネレータ式のように動作することです - クリーンアップされたリストを繰り返し処理し、それを破棄するだけなら問題ありませんが、本当にリストが必要な場合は filter() の呼び出しは list() コンストラクタを使用します。
  • *これらのLispy風味のコンストラクトは、Pythonでは少し異質とされています。2005年頃 グイドは filter - コンパニオンと一緒に mapreduce (まだ消えてはいませんが reduce に移動されました。 ファンクツール が好きな人は一見の価値ありです。 高次関数 ).

4)数学的スタイル

リスト内包 がバージョン 2.0 で導入されて以来、Python のリスト操作の好ましいスタイルとなりました。 PEP 202 . その根拠は、リスト内包は、以下のような状況でリストを作成するための、より簡潔な方法を提供することです。 map()filter() とかネストされたループが現在使われているはずです。

cleaned_list = [ x for x in some_list if x is not thing ]

ジェネレータ式は、バージョン2.4で導入された PEP 289 . ジェネレータ式は、メモリ上に完全なリストを作成する必要がない(または、作成したくない)場合、例えば、要素を一度に一つずつ繰り返し処理したい場合に適しています。リストに対して反復処理を行うだけであれば、ジェネレータ式は次のように考えることができます。 遅延評価 リスト内包

for item in (x for x in some_list if x is not thing):
    do_your_thing_with(item)

注意事項

  1. という不等号演算子を使いたい場合があります。 != の代わりに is not ( この違いが重要です )
  2. リストのコピーを意味するメソッドを批判する人へ:一般に信じられていることとは逆に、ジェネレータ式はリスト内包よりも常に効率的とは限りません。