从字符串列表中删除空字符串


681

我想从python中的字符串列表中删除所有空字符串。

我的想法如下:

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

还有其他pythonic方式可以做到这一点吗?


45
@Ivo,这些陈述都不正确。您永远不要修改for x in list要使用的迭代列表。如果您使用,while loop那么就可以了。演示的循环将删除空字符串,直到不再有空字符串,然后停止。实际上,我什至没有看过这个问题(只是标题),但是我回答的可能性完全相同!如果您不想为了存储而使用解析或过滤器,那是一个非常Python的解决方案。
aaronasterling,2010年

4
永远不要更改您要遍历的列表仍然是一个非常有效的观点:)
Eduard Luca

1
@EduardLuca如果要遍历列表是要更改它,那么这与您应该做的相反。您只需要小心,就可以知道自己不会引起意想不到的行为。
JFA

1
@ EduardLuca,@ JFA:重点是他没有遍历任何列表。他愿意以表格的形式写东西for var in list:,但是在这里,他已经写了while const in list:。这并没有遍历任何东西。它只是重复相同的代码,直到条件为假。
卡蒙(Camion)

Answers:


1149

我会使用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
如果你按性能,itertoolifilter甚至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结果的评估是懒惰的,而不是一go而就的-我认为在大多数情况下ifilter是更好的选择。有趣的是,使用filter它仍然比包装ifilterin 更快list
汉弗莱·鲍嘉

3
如果对一个数字列表执行此操作,请注意,零也将被删除(注意:我仅使用前三种方法),因此您将需要一个替代方法。
SnoringFrog 2014年

2
这仅关注速度,而不关注解决方案的pythonic(提出的问题)。List Comprehensions是pythonic解决方案,仅当分析证明listcomp是瓶颈时才应使用filter。
Tritium21

3
@ whoever-mentions-about-or-imply-Python-3,请仅编辑和更新答案。当问这个问题时,我们只是在讨论Python 2,甚至Python 3发行了将近两年。但是请同时更新Python 2和3的结果。
livibetter

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()]
Bond

67

过滤器实际上对此有一个特殊的选择:

filter(None, sequence)

它将滤除所有评估为False的元素。此处无需使用实际的可调用对象,例如bool,len等。

和map(bool,...)一样快


5
实际上,这是一个python习语。这也是我唯一一次仍然使用filter(),列表推导已经接管了其他所有地方。
kaleissin

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"]
如果要改用filtermethod,可以执行like
list(filter(lambda item: item.strip(), strings))。这给出了相同的结果。


12

代替if x,我将使用if X!=”来消除空字符串。像这样:

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

这将在列表中保留“无”数据类型。此外,如果您的列表中有整数,并且0是其中的一个,它也将被保留。

例如,

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

2
如果您的列表具有不同的类型(无除外),则可能会有更大的问题。
Tritium21

什么类型的 我尝试了int和其他数字类型,字符串,列表,元组,集合和None,并且在那里没有问题。我可以看到,如果有任何不支持str方法的用户定义类型可能会出现问题。我应该担心其他吗?
thiruvenkadam

1
如果您有str_list = [None, '', 0, "Hi", '', "Hello"],则表明应用程序设计不佳。在同一列表中,您不应有多个接口(类型)和“无”。
Tritium21

3
从数据库检索数据?自动测试时函数的参数列表?
thiruvenkadam

3
这些通常是元组。
Tritium21

7

根据列表的大小,如果您使用list.remove()而不是创建新列表,则可能是最有效的:

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

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

这具有不创建新列表的优点,但是具有每次都必须从头开始搜索的缺点,尽管与while '' in l上面建议的用法不同,它每次出现时仅需要搜索一次''(当然,有一种方法可以保持最佳状态)两种方法,但更为复杂)。


1
您可以执行来就地编辑列表ary[:] = [e for e in ary if e]。更干净,不使用异常进行控制。
Krzysztof Karski

2
好吧,这并不是真正的“到位”-我很确定这会创建一个新列表,并将其分配给旧名称。
安德鲁·贾菲

由于每次删除时数据的尾部都会在内存中乱序播放,因此执行效果非常差。最好一次性删除所有内容。
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

感谢dude,它为我带来了一点点变化。即space_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。您没有被忽略。您尚未受到任何不赞成投票的人的攻击。您已收到反馈。放大:滤纸你提出的第一个参数是有过之而无不及lambda x: len(x)是不如lambda x : x这是最坏的选择答案的4个解决方案。正确的功能是首选,但还不够。将光标悬停在向下投票按钮上:提示“此答案无用”。
约翰·马钦

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']

比较我的电脑上的时间

>>> 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

1
报告join解决方案时,@ BenPolinsky 将使用空格分割字符串,但过滤器不会。谢谢您的评论,我的回答有所改善。
Paolo Melchiorre'8

-1

总结最佳答案:

1.消除空洞而无需剥离:

也就是说,保留所有空格字符串:

slist = list(filter(None, slist))

优点:

  • 最简单
  • 最快(请参见下面的基准)。

2.去除剥离后的空容器...

2.a ...当字符串在单词之间不包含空格时:

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

优点:

  • 小代码
  • 快速(但由于内存原因,对于大型数据集而言并非最快,这与@ paolo-melchiorre结果相反)

2.b ...字符串在单词之间包含空格吗?

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

优点:

  • 最快的;
  • 代码的可理解性。

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', '?', '?']
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.