ChatGPT解决这个技术问题 Extra ChatGPT

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

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

我的想法是这样的:

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

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

@Ivo,这些陈述都不是真的。您永远不应该修改您使用 for x in list 迭代的列表 如果您使用的是 while loop 那就没问题了。演示的循环将删除空字符串,直到没有更多的空字符串然后停止。实际上我什至没有看过这个问题(只是标题),但我回答的可能是完全相同的循环!如果您不想为了记忆而使用理解或过滤器,这是一个非常 Pythonic 的解决方案。
永远不要更改您正在迭代的列表仍然是一个非常有效的观点:)
@EduardLuca 如果迭代列表的目的是更改它,那么这与您应该做的相反。您只需要小心,您知道这样做不会导致意外行为。
@EduardLuca,@JFA:关键是他没有遍历任何列表。如果他以 for var in list: 的形式写了一些东西,他会这样做,但在这里,他写的是 while const in list:。这不是迭代任何东西。它只是重复相同的代码,直到条件为假。
您可以使用过滤器删除空字符串。代码应如下所示... data = list(filter(None, str_list))

w
wim

我会使用 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))

如果您那么追求性能,itertool's 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
@cpburnz 非常正确。但是,对于 ifilter,结果的评估是懒惰的,而不是一次性的——我认为在大多数情况下,ifilter 更好。有趣的是,使用 filter 仍然比将 ifilter 包装在 list 中更快。
如果您对数字列表执行此操作,请注意也会删除零(注意:我只使用了前 3 种方法),因此您需要另一种方法。
这仅关注速度,而不是解决方案的pythonic(被问到的问题)。 List Comprehensions 是 Pythonic 解决方案,只有在分析证明 listcomp 是瓶颈时才应使用过滤器。
@whoever-mentions-about-or-imply-Python-3,请编辑和更新答案。当被问到这个问题时,我们只是在讨论 Python 2,即使 Python 3 发布了将近 2 年。但请更新 Python 2 和 3 结果。
w
wim

使用 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()]
[x for x in strings if x] 这很好用,但请解释一下这个循环是如何工作的?
@AmarKumar 在 Python 中,当在布尔上下文中宣布时,空白字符串的计算结果为 false,例如在 if x 中。方括号、for 循环和 if 子句组合起来读取 “如果 x 实际包含某些内容,则为 strings 中的每个元素生成一个由 x 组成的列表。” @ Ib33x 绝对很棒的工作。这个答案肯定是最 Pythonic 的。
I
Ivo van der Wijk

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

filter(None, sequence)

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

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


事实上,这是一个 python 习语。这也是我唯一一次仍然使用 filter(),列表推导已经接管了其他任何地方。
与列表比较相比,我发现这更容易看出代码的意图
A
Aziz Alto
>>> 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', ' '] 你有没有其他解决方案可以在列表中的项目中保留空格但删除其他项目?
请注意,filter(None, lstr) 不会删除带有空格的空字符串 ' ' 是的,因为那不是空字符串。
救命恩人🤓!!
s
ssi-anik

@Ib33X 的回复很棒。如果要删除每个空字符串,请在剥离后。您也需要使用剥离方法。否则,如果它有空格,它也会返回空字符串。就像,“”对于那个答案也是有效的。所以,可以通过。

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

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


你能解释一下这个片段吗?通常,x.strip() 返回 False,我们得到了结果,但是这段代码是如何工作的,我不明白其中的逻辑。
@FuadAk 你为什么不问之前做功课? ideone.com/Kb9Tv5 检查输出中“Second”后面的空格
a
ankostis

总结最佳答案:

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 坏的。
t
thiruvenkadam

而不是 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"]

如果您的列表具有不同的类型(None 除外),您可能会遇到更大的问题。
有哪些类型?我尝试使用 int 和其他数字类型、字符串、列表、元组、集合和 None 并且没有问题。我可以看到,如果有任何不支持 str 方法的用户定义类型可能会出现问题。我应该担心其他任何事情吗?
如果您有 str_list = [None, '', 0, "Hi", '', "Hello"],则表明应用程序设计不佳。您不应该在同一个列表中拥有多个接口(类型)和 None。
从数据库中检索数据?进行自动化测试时函数的参数列表?
这些通常是元组。
A
Andrew Jaffe

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

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

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

这样做的好处是不创建新列表,但缺点是每次都必须从头开始搜索,虽然与上面提出的使用 while '' in l 不同,它只需要每次出现 '' 搜索一次(肯定有保持两种方法中最好的方法,但它更复杂)。


您可以通过执行 ary[:] = [e for e in ary if e] 来编辑列表。更干净,并且不使用控制流异常。
好吧,这并不是真正的“到位”——我很确定这会创建一个新列表并将其分配给旧列表。
这表现得很糟糕,因为每次删除时数据的尾部都会在内存中打乱。最好一击删除所有内容。
A
Aditya

你可以使用这样的东西

test_list = [i for i in test_list if i]

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


S
Samuel Dauzon

请记住,如果您想在字符串中保留空格,您可能会使用某些方法无意中删除它们。如果你有这份清单

['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()]
P
Paolo Melchiorre

正如 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() 会拆分此字符串。


这仅在您的字符串不包含空格时才有效。否则,您也会拆分这些字符串。
@BenPolinsky 正如您所报告的 join 解决方案将使用空格分割字符串,但过滤器不会。谢谢你的评论我改进了我的答案。
F
Forest Katsch

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

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


欢迎来到 SO。你没有被忽视。您没有受到任何反对投票者的攻击。您已收到反馈。放大:您为过滤器提出的第一个参数比 lambda x: len(x) 差,这比 lambda x : x 差,lambda x : x 是所选答案中 4 个解决方案中最差的。正确的功能是首选,但还不够。将光标悬停在否决按钮上:它显示“这个答案没有用”。
G
Golden Lion

使用正则表达式和过滤器进行匹配

lstr = ['hello', '', ' ', 'world', ' ']
r=re.compile('^[A-Za-z0-9]+')
results=list(filter(r.match,lstr))
print(results)