我想从 python 中的字符串列表中删除所有空字符串。
我的想法是这样的:
while '' in str_list:
str_list.remove('')
有没有更多的pythonic方式来做到这一点?
for x in list
迭代的列表 如果您使用的是 while loop
那就没问题了。演示的循环将删除空字符串,直到没有更多的空字符串然后停止。实际上我什至没有看过这个问题(只是标题),但我回答的可能是完全相同的循环!如果您不想为了记忆而使用理解或过滤器,这是一个非常 Pythonic 的解决方案。
for var in list:
的形式写了一些东西,他会这样做,但在这里,他写的是 while const in list:
。这不是迭代任何东西。它只是重复相同的代码,直到条件为假。
data = list(filter(None, str_list))
我会使用 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))
使用 list comprehension 是最 Pythonic 的方式:
>>> strings = ["first", "", "second"]
>>> [x for x in strings if x]
['first', 'second']
如果必须就地修改列表,因为有其他引用必须看到更新的数据,则使用切片分配:
strings[:] = [x for x in strings if x]
[x for x in strings if x.strip()]
。
if x
中。方括号、for
循环和 if
子句组合起来读取 “如果 x
实际包含某些内容,则为 strings
中的每个元素生成一个由 x
组成的列表。” @ Ib33x 绝对很棒的工作。这个答案肯定是最 Pythonic 的。
filter 实际上对此有一个特殊的选项:
filter(None, sequence)
它将过滤掉所有评估为 False 的元素。无需在此处使用实际的可调用对象,例如 bool、len 等。
它和 map(bool, ...) 一样快
>>> 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
filter(None, lstr)
不会删除带有空格的空字符串 ' '
是的,因为那不是空字符串。
@Ib33X 的回复很棒。如果要删除每个空字符串,请在剥离后。您也需要使用剥离方法。否则,如果它有空格,它也会返回空字符串。就像,“”对于那个答案也是有效的。所以,可以通过。
strings = ["first", "", "second ", " "]
[x.strip() for x in strings if x.strip()]
答案是["first", "second"]
。
如果你想改用 filter
方法,你可以像
list(filter(lambda item: item.strip(), strings))
那样做。这是给出相同的结果。
总结最佳答案:
1. 在不剥离的情况下消除 emtpties:
也就是说,保留所有空格字符串:
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()
。
filter(None, words)
(已接受的答案),则需要 s and s.strip()
。我更正了上面的 x2 示例函数并删除了 x2 坏的。
而不是 if x,我会使用 if X != '' 来消除空字符串。像这样:
str_list = [x for x in str_list if x != '']
这将在您的列表中保留 None 数据类型。此外,如果您的列表有整数并且 0 是其中之一,它也将被保留。
例如,
str_list = [None, '', 0, "Hi", '', "Hello"]
[x for x in str_list if x != '']
[None, 0, "Hi", "Hello"]
str_list = [None, '', 0, "Hi", '', "Hello"]
,则表明应用程序设计不佳。您不应该在同一个列表中拥有多个接口(类型)和 None。
根据列表的大小,使用 list.remove() 而不是创建新列表可能是最有效的:
l = ["1", "", "3", ""]
while True:
try:
l.remove("")
except ValueError:
break
这样做的好处是不创建新列表,但缺点是每次都必须从头开始搜索,虽然与上面提出的使用 while '' in l
不同,它只需要每次出现 ''
搜索一次(肯定有保持两种方法中最好的方法,但它更复杂)。
ary[:] = [e for e in ary if e]
来编辑列表。更干净,并且不使用控制流异常。
你可以使用这样的东西
test_list = [i for i in test_list if i]
其中 test_list 是要从中删除空元素的列表。
请记住,如果您想在字符串中保留空格,您可能会使用某些方法无意中删除它们。如果你有这份清单
['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]
space_clean_list = [x.strip() for x in y if x.strip()]
正如 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()
会拆分此字符串。
join
解决方案将使用空格分割字符串,但过滤器不会。谢谢你的评论我改进了我的答案。
使用 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
这是最直观的方法,并且可以在适当的时间内完成。
lambda x: len(x)
差,这比 lambda x : x
差,lambda x : x
是所选答案中 4 个解决方案中最差的。正确的功能是首选,但还不够。将光标悬停在否决按钮上:它显示“这个答案没有用”。
使用正则表达式和过滤器进行匹配
lstr = ['hello', '', ' ', 'world', ' ']
r=re.compile('^[A-Za-z0-9]+')
results=list(filter(r.match,lstr))
print(results)
itertool
'sifilter
会更快——>>> 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
。ifilter
,结果的评估是懒惰的,而不是一次性的——我认为在大多数情况下,ifilter
更好。有趣的是,使用filter
仍然比将ifilter
包装在list
中更快。