Python:如何将逗号分隔的字符串直接拆分为集合

6

我有一些代码,做了以下操作:

if string in comma_delimited_string.split(','):
    return True

这个网站说使用集合和字典进行成员测试比使用列表或元组要快得多。我知道使用set(comma_delimited_string.split(','))并不能提高速度,因为在转换成集合之前仍然会创建一个列表(或者至少,在我计时时似乎会减慢速度)。

那么,我想知道(主要是出于好奇而不是真正有益于我的代码),是否有一种方法可以直接创建一个集合来实现与comma_delimited_string.split(',')相同的效果,而不是创建一个列表,以加快上述操作的速度?

3个回答

8
你忽略了一个事实,那就是为了将任何东西转换为集合,你需要迭代它。而这个迭代过程与你已经执行的搜索原始列表的过程完全相同。因此在这样做中不可能有任何优势,只会增加额外开销。
如果你要多次执行搜索操作,使用集合进行搜索会更有效率,因为这样可以分摊转换的成本。但是转换本身总是需要进行线性扫描的;没有办法避免这一点。

我的推理是,例如,对于一个已经创建好的元素相同的列表和集合'1'、'2'、'3'... '1000000',检查'1000000' in my_set要比'1000000' in my_list快得多,至少我计时的时候是这样。鉴于此,如果有一种方法可以将逗号分隔的字符串直接转换为集合,并且需要与.split方法花费相同的时间,那么实际成员测试的速度可能会加快。 - dieggsy
想法:我猜将逗号分隔的字符串转换为集合与.split一样快的唯一方法可能是以某种方式在C中编写自定义实现,正如你所说,这会带来额外开销。 - dieggsy

3
不,使用 str.split 操作总是返回一个列表,试图将其转换为 set 将会花费时间。编写自己手工制作的能够直接产生一个集合的 split 也会更慢,因为 str.split 是用 C 实现的(源代码应该在 Objects/stringlib/split.h 下面)。
但请注意,如果您的 string 不包含逗号 并且 您期望 string 不是由 split 返回的元素的子字符串,则可以直接执行以下操作:
if string in comma_delimited_string:

如果string包含逗号,那么您的测试将始终失败(因为根据定义,text.split(',')中的元素永远不会包含一个逗号)。
上述条件失败的情况是当您拥有以下内容时:
if "a" in "aaa,bb,c".split(',')

因为在这种情况下,"a" in ["aaa", "bb", "c"] 失败了。
或者,您可以使用正则表达式:
import re
if re.search(r'(^{0},)|(,{0},)|(,{0}$)|(^{0}$)'.format(re.escape(string)), comma_delimited_string):

然而,我不知道这样是否更快,这可能取决于您的输入。

@Bakuriu 感谢回复 - 在我的情况下,我正在处理相当模糊的文档编号(例如可以有文档'10''103'),因此纯粹的string in comma_delimited_string并不太适用。所以我想你是说从逗号分隔的字符串直接转换成集合的唯一快速方法是用C编写?...不打算那么快去做。 - dieggsy
@therockmandolinist 是的,这就是我的意思。你需要复制并粘贴split的代码,并使用集合而不是列表。这会带来很多麻烦,所以只有在必须尽可能快地进行检查时才这样做... - Bakuriu

1

虽然在现有集合上进行成员测试可能比在列表上快(O(1)),但仍需要从字符串创建集合,这将是O(n)。因此,您无法解决时间复杂度的问题。

但是,您可以通过仅扫描字符串而不构建中间数据结构来加速测试的速度,这样可以提高一个常数倍:

(',%s,' % string) in (',%s,' % comma_delimited_string)

除非你有非常好的理由,否则不要使用这个。


是的,我的意思是将字符串转换为集合所需的时间应该与.split方法将其转换为列表的时间相同,这将加速成员测试。不过你的回复很有趣,这确实与检查任何给定字符串是否为列表成员的方式相同。那你为什么说它不应该被使用呢? - dieggsy
很好,在我的测试数据上,这只花费了500纳秒,而不是split的2.5微秒。但从可读性的角度来看,如果速度不是最重要的,我认为应该选择split - tobias_k
@tobias_k 我理解你的观点,对于非常复杂的优化来说这是很有道理的。我想这可能只是个人偏好的问题,但总的来说,我更喜欢在性能和可读性之间进行权衡,特别是如果(像在这种情况下)牺牲不太大的话。不过我最近才真正开始编码,也许你可以说服我改变看法。 - dieggsy
1
除非您已经在实际条件(实际输入数据、硬件等)下对代码进行了分析,并将此表达式确定为可接受性能的瓶颈,否则进行这种微小优化是不值得的。如果性能很重要,请专注于选择正确的算法。可读性强的代码更容易调试、扩展和协作。 - emulbreh
@emulbreh 不知道是否可以麻烦您提供更多信息?您的意思是,如果您尚未证明它对您正在使用的实际代码提供了实质性的好处,那么这并不值得吗?外部测试显示它更快速难道不足以说明问题吗?我并不是在挑战您,只是真心想知道。 - dieggsy
1
问题不在于它是否更快,而在于如果它变得更快,你会获得什么,如果它变得不太可读,你会失去什么。查找“过早优化”以了解这种权衡的讨论。 - emulbreh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接