代码之家  ›  专栏  ›  技术社区  ›  Jean-François Fabre

根据参数类型设置issubset性能差异

  •  4
  • Jean-François Fabre  · 技术社区  · 7 年前

    为什么问这个问题?

    我想回答这个问题: Check if All Values Exist as Keys in Dictionary 有比发电机更好的理解力 all (与某些函数执行的隐式循环相比,即使在理解中,python循环也会减慢执行速度):

    all(i in bar for i in foo)
    

    哪里 bar 是一本字典 foo 是通过使用 set.issubset (转换为 set 属于 能够使用 foo.issubset(bar) ,但没有成功地击败 全部的 解决方案(除非两个容器都转换为 设置 s)。

    我的问题:

    set :

    注意,union()、intersection()、difference()和symmetric_difference()、issubset()和issuperset()方法的非运算符版本将 接受任何有争议的论点 . 相反,它们基于运算符的对应项要求它们的参数是集。这就排除了set('abc')&cbs'等容易出错的结构,转而使用可读性更强的set('abc').intersection('cbs')。

    好吧,但是性能确实取决于参数的类型,即使复杂性不是( The complextiy of Python issubset() ):

    import timeit
    foo = {i for i in range(1, 10000, 2)}
    bar = foo - {400}
    n=10000
    x = timeit.timeit(setup="foo = {str(i) for i in range(1, 10000, 2)};bar = foo - {'400'}",stmt="bar.issubset(foo)",number=n)
    print("issubset(set)",x)
    x = timeit.timeit(setup="foo = {str(i) for i in range(1, 10000, 2)};bar = foo - {'400'};foo=list(foo)",stmt="bar.issubset(foo)",number=n)
    print("issubset(list)",x)
    x = timeit.timeit(setup="foo = {str(i):i for i in range(1, 10000, 2)};bar = set(foo) - {'400'}",stmt="bar.issubset(foo)",number=n)
    print("issubset(dict)",x)
    x = timeit.timeit(setup="foo = {str(i):i for i in range(1, 10000, 2)}.keys();bar = set(foo) - {'400'}",stmt="bar.issubset(foo)",number=n)
    print("issubset(dict_keys)",x)
    

    我的结果(Python3.4):

    issubset(set) 1.6141405847648826
    issubset(list) 3.698748032058883
    issubset(dict) 3.6300025109004244
    issubset(dict_keys) 4.224299651223102
    

    所以如果 设置 作为参数传递,结果非常快。

    使用A list 要慢得多。我发现这是因为必须对字符串进行哈希运算的代价很高。所以我用如下整数更改了测试输入:

    foo = {i for i in range(1, 10000, 2)}
    bar = foo - {400}
    

    结果在全球范围内更快,但仍然存在巨大的时间差异:

    issubset(set) 0.5981848205989139
    issubset(list) 1.7991591232742143
    issubset(dict) 1.889119736960271
    issubset(dict_keys) 2.2531574114632678
    

    我也试着改变 dict 通过 dict.keys() 在python 3中,键被称为( https://www.python.org/dev/peps/pep-3106/ )“一个集合状或无序的容器对象”。

    但在这种情况下,结果比 双关语 列表 .

    为什么要通过一个 设置 比通过一个 列表 或A 双关语 或A dict_keys 对象? 我在文件中没有提到这件事。

    1 回复  |  直到 7 年前
        1
  •  3
  •   user2357112    7 年前

    这个 set.issubset algorithm 需要一个集合才能使用(frozensets和subclasses count);如果传递其他内容,它将生成一个集合。基本上 all(elem in other for elem in self) ,它需要知道 elem in other 是有效的,意味着它对集合的意义。它知道如何保证的唯一方法就是 other 是一组。做一套很贵。

    (我已经掩盖了一些细节。如果您想知道到底发生了什么,特别是如果您有一个奇怪的set子类,请阅读链接中的源代码。)