【问题标题】:Python: Split a comma-delimited string directly into a setPython:将逗号分隔的字符串直接拆分为一个集合
【发布时间】:2016-11-12 18:27:32
【问题描述】:

我有一些类似的代码:

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

This website 表示使用集合和字典的成员资格测试比使用列表或元组快得多。我知道做set(comma_delimited_string.split(',')) 不会提高速度,因为在将其转换为集合之前仍在创建列表(或者至少,当我计时时它似乎减慢了它的速度)。

当时我想知道,(主要是出于好奇而不是对我的代码真正的好处),有没有一种方法可以实现与comma_delimited_string.split(',') 相同的效果,但直接创建一个集合而不是列表,以加快速度把上面的操作搞定了吗?

【问题讨论】:

    标签: python string performance optimization


    【解决方案1】:

    您忽略了一个事实,即为了将任何内容转换为集合,您需要对其进行迭代。并且该迭代与您为搜索原始列表所做的完全相同。所以这样做没有任何优势,只有开销。

    如果您多次搜索一组数据,效率会更高,因为这样可以摊销转换成本。但是转换本身总是线性扫描;没有办法避免这种情况。

    【讨论】:

    • 好吧,我的推理是,例如,对于已经创建的列表并设置了相等的成员 '1'、'2'、'3'、... '1000000',检查 @ 987654321@ 比'1000000' in my_list 快很多,至少在我计时时是这样。鉴于此,如果有一种方法可以将逗号分隔的字符串直接转换为一个集合,该方法可能需要与 .split 方法相同的时间,那么实际的成员资格测试可能会加快。
    • 想法:我猜想将逗号分隔的字符串转换为与.split 一样快的集合的唯一方法可能是以某种方式在 C 中编写自定义实现,正如您所说,这会产生开销。
    【解决方案2】:

    不,str.split 操作总是返回一个列表,尝试将其转换为 set 将花费时间。还要自己手工写split直接生成set会比较慢,因为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 不是不太适用。所以我猜你是说将逗号分隔的字符串直接转换为与.split 一样快的集合的唯一方法是用C 编写它? ....不会很快这样做。
    • @therockmandolinist 是的,这就是我要说的。您必须复制并粘贴split 的代码并使用集合而不是列表。这很麻烦,所以我只会在检查必须尽可能快的关键时才这样做......
    【解决方案3】:

    虽然对现有集合的成员资格测试 (O(1)) 可能比在列表 (O(n)) 上更快,但您仍然需要从字符串创建集合,这将是 O(n )。所以对于时间复杂度你无能为力。

    您可以通过仅扫描字符串而不是构建中间数据结构来加快测试速度:

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

    除非你有充分的理由,否则不要使用它。

    【讨论】:

    • 是的,我的意思是在.split 方法将其转换为列表的时间内将字符串转换为集合,从而加快成员资格测试。不过有趣的回复是,这与检查列表中任何给定字符串的成员身份的方式相同。为什么说不应该使用?
    • 很好,根据我的测试数据,split 只用了 500ns 而不是 2.5µs。但从可读性的角度来看,如果速度不是最重要的,我认为应该选择split
    • @tobias_k 我理解你的意思,这对于非常复杂的优化很有意义。我想这可能只是一个偏好问题,但我认为总的来说我更喜欢优化性能而不是可读性,特别是如果(在这种情况下)牺牲不是太大。不过,我最近才真正进入编码领域,所以也许你可以说服我。
    • 除非您已经在真实条件下(真实输入数据、硬件等)分析了您的代码并将此表达式确定为可接受性能的瓶颈,否则不值得进行这种类型的微优化。如果性能很重要,请专注于选择正确的算法。可读代码更易于调试、扩展和协作。
    • 问题不在于它是否更快,而是你会从更快的速度中获得什么,以及如果可读性降低你会失去什么。查找“过早优化”以讨论这种权衡。
    猜你喜欢
    • 1970-01-01
    • 2019-07-29
    • 2018-12-21
    • 2021-02-24
    • 1970-01-01
    • 2014-01-03
    • 2015-03-07
    相关资源
    最近更新 更多