从字典值中获得第一个值的最快和最好的方法是什么?有多种技术,但什么是最好的(内存和速度),为什么?
下面是一些例子。我也希望有其他技巧:
dictis = {
1: "One"
, 2: "Two"
, 3: "Three"
, 4: "Four"
}
# 1 technique:
#----------------
value = next(iter(dictis.values()))
print(value)
# 2 technique:
#----------------
value = list(dictis.values())[0]
print(value)
# 3 technique:
#----------------
value = [value for value in dictis.values()][0]
print(value)
# 4 technique:
#----------------
value = next(value for value in dictis.values())
print(value)发布于 2021-12-26 21:40:16
TL;博士
用第一条路!对于大词典来说,它比第四快2.5倍,比第二(10000倍)和第三(20000倍)快得多,当词典变大时,增加得更多。第二和第三种方法创建完整列表并消耗O(n)内存
时间测量
用于小型词典:
size = 10
dictis = {i: str(i) for i in range(size)}
code1 = "value = next(iter(dictis.values()))"
code2 = "value = list(dictis.values())[0]"
code3 = "value = [value for value in dictis.values()][0]"
code4 = "value = next(value for value in dictis.values())"
kw = {"number": 1000000, "globals": globals()}
print("code1: ", timeit.timeit(code1, **kw)) # 0.15313154199999998
print("code2: ", timeit.timeit(code2, **kw)) # 0.25568722099999996
print("code3: ", timeit.timeit(code3, **kw)) # 0.49292356800000003
print("code4: ", timeit.timeit(code4, **kw)) # 0.43500832200000006让我们检查一下size = 1_000_000。第二和第三种方法持续时间很长(number = 100)
code1: 1.7961999999982492e-05
code2: 1.607245366
code3: 3.3421025739999997
code4: 6.061599999984679e-05对于number = 10_000_00
code1: 1.7192588249999998
code4: 4.457956223发布于 2021-12-26 22:29:32
让我们谈谈几点。首先,Python字典并不总是按标准排序,它取决于版本。在实现方面,它们在Python3.5之前具有任意顺序,这意味着如果在中间时间对字典进行更改,那么在不同时间发出的相同list(dictis)调用可以返回不一致顺序列表。所以,不要在3.5或更低的时间内这样做。Python实际上有几种不同的实现方式,最常见的是CPython,而另一种流行的方法是PyPy。在这两种情况下,字典的实现方式都保持了插入顺序。从3.6开始,CPython就是这样的。记住:字典的顺序只是插入元素的顺序,它与元素的属性无关。
第二,"O(n)“和"O(1)”指的是大-O表示法,这是渐近表示法中的一个主题。维基百科上有关于这些的文章,但它们可以是相当技术性的。我建议阅读一本算法教科书,比如Cormen的。其主旨是:括号内的数字代表一个“乘数”,表示你希望你的算法能执行多少步。如果希望至少循环一次n项列表中的每个项,则算法是"O(n)“(昵称为”线性时间“)。如果您只希望看到1或2或任何数目的项目是固定的,永远不会改变,那么您是"O(1)“(昵称为”恒定时间“)。正如khelwood对你的问题所评论的那样,第一个选择是O(1)。这是因为iter函数向字典返回一个迭代器,而next方法一次只查看一个元素。我不知道字典迭代器在CPython (3.6-3.10)中的实际实现是O(1),但理论上应该是。技巧2和3将字典转换为列表,这意味着他们必须访问每个元素,因此必须采取更多的步骤。技术4使用生成器实现与技术1类似的效果,但考虑起来更复杂,灵活性更低。
不过,技术1和4使用函数values来获得字典值的“视图”。我不知道这是多少工作的引擎盖(这可能是O(n),就我所知),所以我认为我们应该切断中间的人。这应该是一个更好的解决方案:
key = next(iter(dictis)) # this doesn't ask to generate a view object
value = dictis[key] # this is instant look-up我做了一些测试,这个解决方案实际上与技术1相当,所以生成字典值的视图似乎不需要太多开销。使用与kosciej16 16的答案相同的测试,使用size = 1_000_000、number = 10_000和
code5 = '''
key = next(iter(dictis))
value = dictis[key]
'''我得到了
>>> print("code1: ", timeit.timeit(code1, **kw))
code1: 0.002648300000146264
>>> print("code4: ", timeit.timeit(code4, **kw))
code4: 0.0054308000001128676
>>> print("code5: ", timeit.timeit(code5, **kw))
code5: 0.0028101000000333443但我可以提供一个更好的解决方案,但这需要更多的工作吗?如果您想要跟踪元素被插入到集合中的顺序,那么使用队列会给您带来很多好处。你可以查阅有关算法教科书的细节。基本上,它是一种数据结构,可以跟踪插入的顺序。您可能需要将数据存储在对象中,这在内存方面更为昂贵。
class Objectis():
def __init__(self, id, data):
self.id = id
self.data = data然后制作一堆这样的东西:
item1 = Objectis(1, "One")
item2 = Objectis(2, "Two")
item3 = Objectis(3, "Three")
item4 = Objectis(4, "Four")将它们添加到任何顺序的列表中:
queue = [] # you should start your queue empty
queue.append(item3)
queue.append(item1)
queue.append(item2)
queue.append(item4)如果你想知道谁是第一个,你可以立即使用queue[0]。如果你想知道谁是最后一个,就做queue[-1]吧。如果要删除第一个元素,可以执行element = queue.pop(0)。如果要在第一个位置插入元素,可以执行queue.insert(0, element)。
https://stackoverflow.com/questions/70489969
复制相似问题