文字列のリストから空の文字列を削除する


682

Pythonの文字列リストからすべての空の文字列を削除したいのですが。

私の考えは次のようになります:

while '' in str_list:
    str_list.remove('')

これを行うためのもっとpythonicな方法はありますか?


45
@Ivo、これらのステートメントはどちらも真実ではありません。繰り返し使用しているリストを変更してはなりません。使用しているfor x in list場合は問題ありませんwhile loop。示されているループは、空の文字列がなくなるまで空の文字列を削除し、停止します。私は実際には質問(タイトルだけ)も見ていませんでしたが、可能性としてまったく同じループで答えました!記憶のために内包表記やフィルターを使用したくない場合、それは非常にPython的な解決策です。
aaronasterling

4
繰り返しているリストを決して変更しないようにするための非常に有効なポイント:)
Eduard Luca

1
@EduardLucaリストを反復する目的がリストを変更することである場合、それはあなたがすべきことの逆です。そうすることで予期しない動作を引き起こさないことを知っていることに注意する必要があります。
JFA

1
@ EduardLuca、@ JFA:重要なのは、彼がどのリストに対しても繰り返し処理を行わないことです。彼が何かの形for var in list:で書いていたとしたら彼はそうするだろうが、ここでは彼が書いたwhile const in list:。何も繰り返されません。条件が偽になるまで同じコードを繰り返すだけです。
Camion

回答:


1150

私は使用しますfilter

str_list = filter(None, str_list)
str_list = filter(bool, str_list)
str_list = filter(len, str_list)
str_list = filter(lambda item: item, str_list)

Python 3はからイテレータを返すfilterため、への呼び出しでラップする必要がありますlist()

str_list = list(filter(None, str_list))

11
あなたがいるならというパフォーマンスのために押され、itertool「sがifilterさえfaster-です>>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000) 2.3468542098999023>>> timeit('itertools.ifilter(None, str_list)', 'str_list=["a"]*1000', number=100000) 0.04442191123962402
ハンフリーボガート、

4
@cpburnz本当にそうです。ただし、ifilter結果は一気に評価されるのではなく、遅延評価されifilterます。ほとんどの場合、結果が優れていると私は主張します。使用したことは興味深いがfilter、まだ速いラップよりもあるifilterlistかかわらず。
ハンフリーボガート

3
数値のリストに対してこれを行う場合、ゼロも削除されることに注意してください(注:最初の3つの方法のみを使用したため)、別の方法が必要になります。
SnoringFrog 2014

2
これは速度にのみ焦点を当てており、ソリューションのPythonicic(尋ねられた質問)には焦点を当てていません。リスト内包表記はpythonicソリューションであり、listcompがボトルネックであることがプロファイリングによって証明された場合にのみ、フィルターを使用する必要があります。
Tritium21、2015

3
@ whoever-mentions-about-or-imply-Python-3、回答を編集して更新してください。この質問が尋ねられたとき、私たちはPython 2についてのみ議論していました。Python3でさえ、ほぼ2年後にリリースされました。ただし、Python 2と3の両方の結果を更新してください。
livibetter 2016年

236

リスト内包表記の使用は、最もPython的な方法です。

>>> strings = ["first", "", "second"]
>>> [x for x in strings if x]
['first', 'second']

リストをインプレースで変更する必要がある場合、更新されたデータを参照する必要がある他の参照があるため、スライス割り当てを使用します。

strings[:] = [x for x in strings if x]

16
このソリューションは簡単に適応できるので、気に入っています。空の文字列だけでなく空白だけの文字列も削除する必要がある場合は、次のようになります[x for x in strings if x.strip()]
債券

67

filterは実際にはこれのための特別なオプションを持っています:

filter(None, sequence)

Falseと評価されるすべての要素をフィルターで除外します。ここでは、bool、lenなどの実際の呼び出し可能オブジェクトを使用する必要はありません。

map(bool、...)と同じくらい高速です


5
これは、実際にはpythonイディオムです。私が今でもfilter()を使用するのはこのときだけです。リスト内包表記が他のあらゆる場所を引き継いでいます。
kaleissin 14

24
>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']

>>> ' '.join(lstr).split()
['hello', 'world']

>>> filter(None, lstr)
['hello', ' ', 'world', ' ']

時間を比較

>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
4.226747989654541
>>> timeit('filter(None, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.0278358459472656

filter(None, lstr)はスペースを含む空の文字列を削除しないことに注意してください。両方を削除する間' 'だけ削除されます。''' '.join(lstr).split()

filter()空白文字列を削除して使用するには、さらに時間がかかります。

>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
18.101892948150635

単語の文字列の間にスペースがある場合は機能しません。例:['hello world'、 ''、 'hello'、 '']。>> ['helloworld'、 ''、 'hello'、 '']リスト内のアイテム内にスペースを維持し、他のアイテムを削除する他の解決策はありますか?
Reihan_amn

filter(None, lstr)は空白の空の文字列を削除しないことに注意してください' '。これは空の文字列ではないためです。
AMC

15

@ Ib33Xからの返信は素晴らしいです。空の文字列をすべて削除したい場合は、削除してください。stripメソッドも使用する必要があります。それ以外の場合、空白がある場合は空の文字列も返します。たとえば、「」もその回答に有効です。だから、によって達成することができます。

strings = ["first", "", "second ", " "]
[x.strip() for x in strings if x.strip()]

これに対する答えはになります["first", "second"]。 代わりにメソッド
を使用したい場合filterは、のようにすることができます
list(filter(lambda item: item.strip(), strings))。これは同じ結果を与えます。


12

if xの代わりに、空の文字列を削除するためにif X!= ''を使用します。このような:

str_list = [x for x in str_list if x != '']

これにより、リスト内のNoneデータ型が保持されます。また、リストに整数があり、そのうちの1つが0の場合、リストも保持されます。

例えば、

str_list = [None, '', 0, "Hi", '', "Hello"]
[x for x in str_list if x != '']
[None, 0, "Hi", "Hello"]

2
リストに異なるタイプ(Noneを除く)がある場合、より大きな問題が発生する可能性があります。
Tritium21、2015

どんなタイプ?私はintや他の数値型、文字列、リスト、タプ、セット、Noneを試してみましたが、問題はありませんでした。strメソッドをサポートしないユーザー定義型がある場合、問題が発生する可能性があることがわかりました。他のことについて心配する必要がありますか?
thiruvenkadam 2015

1
がある場合str_list = [None, '', 0, "Hi", '', "Hello"]は、アプリケーションの設計が不十分であることを示しています。同じリストに複数のインターフェース(タイプ)とNoneを含めることはできません
トリチウム21 2015

3
データベースからデータを取得していますか?自動テストを行っている間の関数の引数のリスト?
thiruvenkadam 2015

3
それらは通常タプルです。
Tritium21 2015

7

リストのサイズによっては、新しいリストを作成するのではなく、list.remove()を使用するのが最も効率的です。

l = ["1", "", "3", ""]

while True:
  try:
    l.remove("")
  except ValueError:
    break

これには、新しいリストを作成しないという利点がありますが、毎回最初から検索する必要があるという欠点があります。 while '' in l上記の提案、発生ごとに1回だけ検索する必要''があります(確かに最善の方法を維持する方法があります。両方の方法ですが、より複雑です)。


1
リストを編集するには、を実行しary[:] = [e for e in ary if e]ます。はるかにクリーンで、制御フローの例外を使用しません。
Krzysztof Karski 2017年

2
まあ、それは実際には「適切な」ものではありません-これは新しいリストを作成し、古いリストの名前に割り当てるだけだと確信しています。
Andrew Jaffe 2018

削除するたびにデータの末尾がメモリ内でシャッフルされるため、これは非常にうまく機能しません。1回のヒットですべてを削除することをお勧めします。
WIM

7

文字列内の空白を保持したい場合は、いくつかの方法を使用して意図せずに削除する可能性があることください。このリストがあれば

['hello world'、 ''、 ''、 'hello']あなたが望むかもしれないもの['hello world'、 'hello']

最初にリストをトリミングして、任意のタイプの空白を空の文字列に変換します。

space_to_empty = [x.strip() for x in _text_list]

次に、それらのリストから空の文字列を削除します

space_clean_list = [x for x in space_to_empty if x]

文字列内の空白を保持したい場合は、いくつかの方法を使用して意図せずに空白を削除することができます。このアプローチのように?
AMC

おかげで、少し変更を加えてうまくいきました。iespace_clean_list = [x.strip() for x in y if x.strip()]
Muhammad Mehran Khan Attari

6

使用filter

newlist=filter(lambda x: len(x)>0, oldlist) 

指摘したようにフィルターを使用することの欠点は、他の方法よりも遅いことです。また、lambda通常は高価です。

または、すべての中で最も単純で最も反復的な方法を使用できます。

# I am assuming listtext is the original list containing (possibly) empty items
for item in listtext:
    if item:
        newlist.append(str(item))
# You can remove str() based on the content of your original list

これは最も直感的な方法であり、適切な時間で実行できます。


9
SOへようこそ。あなたは無視されていません。あなたは、非名高いダウンボーターに攻撃されていません。あなたはフィードバックを与えられました。増幅:フィルターに対して提案された最初の引数は、選択した回答の4つのソリューションの中で最悪のlambda x: len(x)場合よりも悪いですlambda x : x。正しく機能することが望ましいが、十分ではない。カーソルを下向き投票ボタンの上に置くと、「この回答は役に立ちません」と表示されます。
John Machin 2012年

5

Aziz Alto によって報告されたfilter(None, lstr)ように、空白を含む空の文字列は削除されません' 'が、lstrに文字列のみが含まれていることが確かな場合は、使用できますfilter(str.strip, lstr)

>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(str.strip, lstr)
['hello', 'world']

PCで時間を比較する

>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.356455087661743
>>> timeit('filter(str.strip, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
5.276503801345825

''スペースのある文字列を削除して空にするための最速の解決策が' '残ってい' '.join(lstr).split()ます。

コメントで報告されているように、文字列にスペースが含まれている場合、状況は異なります。

>>> lstr = ['hello', '', ' ', 'world', '    ', 'see you']
>>> lstr
['hello', '', ' ', 'world', '    ', 'see you']
>>> ' '.join(lstr).split()
['hello', 'world', 'see', 'you']
>>> filter(str.strip, lstr)
['hello', 'world', 'see you']

filter(str.strip, lstr)スペースを含む文字列を保持しているのがわかりますが、' '.join(lstr).split()この文字列は分割されます。


1
これは、文字列にスペースが含まれていない場合にのみ機能します。それ以外の場合は、これらの文字列も分割します。
phillyslick 2017

1
joinソリューションを報告した@BenPolinsky はスペースで文字列を分割しますが、フィルターは分割しません。コメントありがとうございます私は私の答えを改善しました。
Paolo Melchiorre 2017

-1

最良の回答を要約します。

1.ストリッピングなしで空を排除します。

つまり、すべてのスペース文字列が保持されます。

slist = list(filter(None, slist))

PRO:

  • 最も単純な;
  • 最速(以下のベンチマークを参照)。

2.ストリッピング後に空を取り除くには...

2.a ...文字列の単語間にスペースが含まれていない場合:

slist = ' '.join(slist).split()

PRO:

  • 小さなコード
  • 高速(ただし、@ paolo-melchiorreの結果とは異なり、メモリが原因で大きなデータセットを使用した場合は最速ではありません)

2.b ...文字列に単語間のスペースが含まれている場合?

slist = list(filter(str.strip, slist))

PRO:

  • 最速。
  • コードの理解可能性。

2018マシンのベンチマーク:

## Build test-data
#
import random, string
nwords = 10000
maxlen = 30
null_ratio = 0.1
rnd = random.Random(0)                  # deterministic results
words = [' ' * rnd.randint(0, maxlen)
         if rnd.random() > (1 - null_ratio)
         else
         ''.join(random.choices(string.ascii_letters, k=rnd.randint(0, maxlen)))
         for _i in range(nwords)
        ]

## Test functions
#
def nostrip_filter(slist):
    return list(filter(None, slist))

def nostrip_comprehension(slist):
    return [s for s in slist if s]

def strip_filter(slist):
    return list(filter(str.strip, slist))

def strip_filter_map(slist): 
    return list(filter(None, map(str.strip, slist))) 

def strip_filter_comprehension(slist):  # waste memory
    return list(filter(None, [s.strip() for s in slist]))

def strip_filter_generator(slist):
    return list(filter(None, (s.strip() for s in slist)))

def strip_join_split(slist):  # words without(!) spaces
    return ' '.join(slist).split()

## Benchmarks
#
%timeit nostrip_filter(words)
142 µs ± 16.8 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit nostrip_comprehension(words)
263 µs ± 19.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter(words)
653 µs ± 37.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_map(words)
642 µs ± 36 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_comprehension(words)
693 µs ± 42.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_generator(words)
750 µs ± 28.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_join_split(words)
796 µs ± 103 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

s and s.strip()単純化することができますs.strip()
AMC

s and s.strip() 完全に複製したい場合に必要です filter(None, words)、受け入れられた答え。上記のx2のサンプル関数を修正し、x2の悪い関数を削除しました。
ankostis

-2

スペースと空の値を組み合わせたリストの場合は、単純なリスト内包表記を使用します-

>>> s = ['I', 'am', 'a', '', 'great', ' ', '', '  ', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', '', 'a', '', 'joke', '', ' ', '', '?', '', '', '', '?']

ご覧のとおり、このリストにはスペースとnull要素の組み合わせが含まれています。スニペットの使用-

>>> d = [x for x in s if x.strip()]
>>> d
>>> d = ['I', 'am', 'a', 'great', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', 'a', 'joke', '?', '?']
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.