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

zer*_*odx 632 python arrays string list

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

我的想法是这样的:

while '' in str_list:
    str_list.remove('')
Run Code Online (Sandbox Code Playgroud)

有没有更多的pythonic方式来做到这一点?

liv*_*ter 1066

我会用filter:

str_list = filter(None, str_list) # fastest
str_list = filter(bool, str_list) # fastest
str_list = filter(len, str_list)  # a bit slower
str_list = filter(lambda item: item, str_list) # slower than list comprehension
Run Code Online (Sandbox Code Playgroud)

Python 3从中返回一个迭代器filter,因此应该包含在调用中list()

str_list = list(filter(None, str_list)) # fastest
Run Code Online (Sandbox Code Playgroud)

()

测试:

>>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000)
2.4797441959381104
>>> timeit('filter(bool, str_list)', 'str_list=["a"]*1000', number=100000)
2.4788150787353516
>>> timeit('filter(len, str_list)', 'str_list=["a"]*1000', number=100000)
5.2126238346099854
>>> timeit('[x for x in str_list if x]', 'str_list=["a"]*1000', number=100000)
13.354584932327271
>>> timeit('filter(lambda item: item, str_list)', 'str_list=["a"]*1000', number=100000)
17.427681922912598
Run Code Online (Sandbox Code Playgroud)

  • 如果你因为表现而被迫,[`itertool`的`ifilter`](http://docs.python.org/library/itertools.html#itertools.ifilter)更快 - ">>> 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`. (7认同)
  • @cpburnz非常真实.然而,对于`ifilter`结果是懒惰地评估,而不是一次性 - 我认为对于大多数情况来说`ifilter`更好.有趣的是,使用`filter`仍然比在`list`中包装`ifilter`更快. (4认同)
  • @ whoever-mentions-about-or-imply-Python-3,请编辑并更新答案.当问到这个问题时,我们只讨论Python 2,即使Python 3发布了差不多2年.但是要更新Python 2和3结果. (3认同)
  • 如果对数字列表执行此操作,请注意也将删除零(注意:我只使用前3种方法),因此您需要一种替代方法. (2认同)
  • 这仅关注速度,而不关注解决方案的 Pythonic 程度(提出的问题)。List Comprehensions 是 Pythonic 的解决方案,只有在分析证明 listcomp 是一个瓶颈时才应该使用过滤器。 (2认同)

Ib3*_*33X 210

列表理解

strings = ["first", "", "second"]
[x for x in strings if x]
Run Code Online (Sandbox Code Playgroud)

输出: ['first', 'second']

编辑:按建议缩短

  • 这个解决方案比``filter(None,my_list)``快x9倍. (47认同)
  • @kee它是否比filter()慢.列表理解是pythonic解决方案. (28认同)
  • 可读代码非常重要.预优化非常危险. (24认同)
  • 我喜欢这个解决方案,因为它很容易适应.如果我不仅要删除空字符串而只删除只是空格的字符串,例如:`[x for x in strings in x.strip()]`. (11认同)
  • 对于所有那些关于这个解决方案的评论的评论者比`filter(None,my_list)`慢得多:https://docs.python.org/2/library/functions.html#filter这个页面说,当第一个参数`filter()`是`None`它相当于`[my_list if item中item的项目]` (10认同)
  • @AmarKumar 在 Python 中,当在布尔上下文中声明时,空白字符串的计算结果为 false,例如“if x”。括号、“for”循环和“if”子句组合起来读取*“如果“x”实际上包含某些内容,则为“strings”中的每个元素生成一个由“x”组成的列表。”* @Ib33x 绝对很棒的工作。这个答案无疑是最 Pythonic 的。 (6认同)
  • 你应该使用pythonic版本的原因是......这更像是过滤器一样快.他们修复并优化了pythonic的使用 (2认同)

Ivo*_*ijk 63

filter实际上有一个特殊的选项:

filter(None, sequence)
Run Code Online (Sandbox Code Playgroud)

它将过滤掉所有评估为False的元素.这里不需要使用实际的可调用语句,如bool,len等.

它和地图一样快(bool,......)

  • 事实上,这是一个蟒蛇成语.这也是我仍然使用filter()的唯一一次,列表推导已经占据了其他地方. (4认同)

Azi*_*lto 22

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

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

>>> filter(None, lstr)
['hello', ' ', 'world', ' ']
Run Code Online (Sandbox Code Playgroud)

比较时间

>>> 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
Run Code Online (Sandbox Code Playgroud)

请注意,filter(None, lstr)不会删除带有空格的空字符串' ',只会''' '.join(lstr).split()删除两者时将其删除.

filter()删除空白字符串,需要花费更多时间:

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


Adi*_*tya 15

你可以使用这样的东西

test_list = [i for i in test_list if i]
Run Code Online (Sandbox Code Playgroud)

其中 test_list 是要从中删除空元素的列表。


ssi*_*nik 12

来自@ Ib33X的回复太棒了.如果要在剥离后删除每个空字符串.你也需要使用strip方法.否则,如果它有空格,它也将返回空字符串.就像,""对于那个答案也是有效的.所以,可以通过实现.

strings = ["first", "", "second ", " "]
[x.strip() for x in strings if x.strip()]
Run Code Online (Sandbox Code Playgroud)

答案就是这样["first", "second"].
如果你想使用filter方法,你可以这样做
list(filter(lambda item: item.strip(), strings)).这给出了相同的结果.


thi*_*dam 11

而不是if,我会使用X!=''来消除空字符串.像这样:

str_list = [x for x in str_list if x != '']
Run Code Online (Sandbox Code Playgroud)

这将在列表中保留None数据类型.此外,如果您的列表有整数,0是其中之一,它也将被保留.

例如,

str_list = [None, '', 0, "Hi", '', "Hello"]
[x for x in str_list if x != '']
[None, 0, "Hi", "Hello"]
Run Code Online (Sandbox Code Playgroud)

  • 如果您的列表具有不同的类型(除了 None),您可能会遇到更大的问题。 (2认同)
  • 从数据库检索数据?自动测试时函数的参数列表? (2认同)
  • 那些通常是元组. (2认同)

And*_*ffe 8

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

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

while True:
  try:
    l.remove("")
  except ValueError:
    break
Run Code Online (Sandbox Code Playgroud)

这样做的好处是不会创建新的列表,但每次都必须从头开始搜索,但不像while '' in l上面提到的那样,它只需要每次搜索一次''(有一种方法可以保持最佳状态)两种方法,但它更复杂).

  • 嗯,这并不是真正“到位”——我很确定这会创建一个新列表并将其分配给旧列表。 (2认同)

小智 7

用途filter:

newlist=filter(lambda x: len(x)>0, oldlist) 
Run Code Online (Sandbox Code Playgroud)

指出使用过滤器的缺点是它比替代品慢; 此外,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
Run Code Online (Sandbox Code Playgroud)

这是最直观的方法,并且在适当的时间内完成.

  • 欢迎来到SO.你没有被忽视.你没有遭到任何无礼的击倒者的攻击.您已收到反馈.放大:你提出的第一个过滤器arg比`lambda x:len(x)`更差,这比`lambda x:x`更糟,这是所选答案中4个解决方案中最差的.正确的功能是首选,但还不够.将光标悬停在downvote按钮上:它显示"此答案无效". (7认同)

ank*_*tis 6

总结最佳答案:

1. 无需剥离即可消除空位:

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

slist = list(filter(None, slist))
Run Code Online (Sandbox Code Playgroud)

优点:

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

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

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

slist = ' '.join(slist).split()
Run Code Online (Sandbox Code Playgroud)

优点:

  • 小代码
  • 快(但由于内存原因,大数据集不是最快的,与@paolo-melchiorre 结果相反)

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

slist = list(filter(str.strip, slist))
Run Code Online (Sandbox Code Playgroud)

优点:

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

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)
Run Code Online (Sandbox Code Playgroud)


Rei*_*amn 6

请记住,如果要将白色空格保留在字符串中,可以使用某些方法无意中删除它们.如果你有这个清单

['你好世界','','','你好']你可能想要什么['你好世界','你好']

首先修剪列表以将任何类型的空格转换为空字符串:

space_to_empty = [x.strip() for x in _text_list]
Run Code Online (Sandbox Code Playgroud)

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

space_clean_list = [x for x in space_to_empty if x]
Run Code Online (Sandbox Code Playgroud)

  • _如果你想保留字符串中的空格,你可能会使用某些方法无意中删除它们。_那么像这种方法吗? (2认同)

Pao*_*rre 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']
Run Code Online (Sandbox Code Playgroud)

比较我的电脑上的时间

>>> 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
Run Code Online (Sandbox Code Playgroud)

删除''和清空带有空格的字符串的最快解决方案' '仍然存在' '.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']
Run Code Online (Sandbox Code Playgroud)

您可以看到filter(str.strip, lstr)保留带有空格的字符串,但' '.join(lstr).split()会拆分此字符串.

  • @BenPolinsky 正如您所报告的“join”解决方案将用空格分割字符串,但过滤器不会。感谢您的评论我改进了我的答案。 (2认同)