【问题标题】:python fastest 'structure' access implementationpython最快的“结构”访问实现
【发布时间】:2020-04-02 11:49:25
【问题描述】:

我有一个数据结构,它由固定数量的字段和一个递归函数组成,该函数对这些结构的列表进行一些处理。在每次迭代中,该函数都会访问某个特定的列表元素(数据结构),分析其所有字段并(基于字段值)通过删除或添加新的数据结构元素来修改列表。

我想知道实现这种数据结构的最有效方法是什么?我想最敏感的方面是创建新结构和访问结构字段。我对具有 10 个字段的结构进行了一些测试:

  1. 作为列表实现:
print("List")

def list_f ():
  l = [1,2,3,4,5,6,7,8,9,10]
  a1 = l[0]
  a2 = l[1]
  a3 = l[2]
  a4 = l[3]
  a5 = l[4]
  a6 = l[5]
  a7 = l[6]
  a8 = l[7]
  a9 = l[8]
  a10 = l[9]

print(timeit("list_f()", "from __main__ import list_f"))

输出:

List
0.4056466743350029
  1. 作为字典实现:
print("Dict")

def dict_f ():
  d = {"1":1, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "10":10}
  a1 = d["1"]
  a2 = d["2"]
  a3 = d["3"]
  a4 = d["4"]
  a5 = d["5"]
  a6 = d["6"]
  a7 = d["7"]
  a8 = d["8"]
  a9 = d["9"]
  a10 = d["10"]

print(timeit("dict_f()", "from __main__ import dict_f"))

输出:

Dict
0.6061008963733912
  1. 作为类实现:
print("Class")

class C (object):
  
  def __init__(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10):
    self.a1 = a1
    self.a2 = a2
    self.a3 = a3
    self.a4 = a4
    self.a5 = a5
    self.a6 = a6
    self.a7 = a7
    self.a8 = a8
    self.a9 = a9
    self.a10 = a10

def class_f ():
  c = C(1,2,3,4,5,6,7,8,9,10)
  a1 = c.a1
  a2 = c.a2
  a3 = c.a3
  a4 = c.a4
  a5 = c.a5
  a6 = c.a6
  a7 = c.a7
  a8 = c.a8
  a9 = c.a9
  a10 = c.a10

print(timeit("class_f()", "from __main__ import class_f, C"))

输出:

Class
1.2926895800046623

在我看来,列表是最有效的解决方案。您是否知道我可以尝试的任何其他实现,或者这些执行时间如何取决于结构字段的数量和类型?

编辑:

澄清一下,字段不具有相同的类型(我只是在示例中使用了所有int-s),会有一些字符串,一些对象句柄等等...... 我永远不必即时修改字段。我知道在创建结构时希望它们具有什么值,因此我将初始化它们并将结构插入到列表中。该函数仅读取这些值并在完成时从列表中删除整个结构(并且可以选择创建全新的结构并将其插入输入列表中)。我是定义结构和函数的人,因此我可以调整函数以有效地与任何实现一起工作。

【问题讨论】:

  • 恭喜!您刚刚发现设置 dict 比设置列表更昂贵,自定义 Python 类比设置 dict 更昂贵。但我不确定这与关于在递归函数中修改结构的问题有什么关系......
  • 为了让你的“基准”有意义,你应该在被测函数之外构建列表/字典/类实例,并且只有函数中的访问部分。
  • 你忘了测试tuple FWIW - 从语义上讲,它是你使用列表的正确类型。
  • 感谢@brunodesthuilliers,但我认为创建结构所需的时间也需要考虑在内,因为该函数还可以将新结构添加到列表中。元组给了我:元组 0.32156257471069694
  • “还需要考虑创建结构所花费的时间,因为该函数还可以将新结构添加到列表中” => 嗯,确实如此 - 但您仍然应该分别测试两者得到有用的结果。

标签: python performance data-structures


【解决方案1】:

您的问题的答案取决于您需要执行哪些操作以及您要在容器中存储哪些数据类型。 对于您给出的示例,list 是最有意义的。

假设您的观点是加速您的代码,您的替代方案是使用矢量化。例如,如果您要对每个元素执行相同的操作,并且您的元素是数字,那么您可以使用numpy.ndarray,它将使用矢量化方法来明智地执行操作 elemet。 避免正常的 python 循环会显着减少执行时间。

【讨论】:

    【解决方案2】:

    如果您事先已经知道所需元素的位置,列表会很有效。如果你有一个键并且你想访问一个值,那么字典有一个优势,这可以在恒定时间内完成。列表访问也是线性时间操作,但在位置未知的情况下查找不是,因为它需要遍历元素直到找到正确的元素。

    根据您的描述,我会说字典是最清晰(如代码清晰)的结构。

    【讨论】:

    • "如果您事先已经知道所需元素的位置,列表是有效的。" => 元组也是如此 - 这实际上就是它们的用途,具有重要位置的异构集合(您首先知道pos 是 X,第二个 Y 等等)。
    【解决方案3】:

    列表是可编辑的对象,元组不是,字典是无序的基于键的数据结构,而不是基于索引的列表和元组。谈到性能,元组和列表比字典略快,但可读性很重要。因此,如果这些值有意义(可能 a1 是某物的高度,a2 是宽度,a3 是房间中蛇的数量等等),您应该考虑使用字典。如果它们是过去 10 小时的 BTC 价格(所有值的一个含义),您可以使用列表。元组用的不多。

    【讨论】:

    • 如果您为索引定义伪常量,元组与 dicts 一样“可读” - 并且它们已被使用,至少被知道它们用途的人所使用。
    • 我知道,但它们仍然没有太多使用
    【解决方案4】:

    经过一些额外的测试,我发现,正如@{bruno desthuilliers} 所建议的那样,元组提供了最短的访问时间,因此以这种方式实现。

    【讨论】:

      猜你喜欢
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 2013-10-11
      • 2012-10-17
      • 1970-01-01
      • 2014-08-21
      • 2013-04-19
      • 2023-03-21
      相关资源
      最近更新 更多