下面的代码使用与 Patrick Haugh 的回答类似的策略,除了它还维护您的字典。正如帕特里克的回答一样,我们将幂值放在元组的开头,以便它被堆正确排序。我们将整数键附加到进入堆的元组的末尾,因为我们需要它来删除已被取代的 dict 项。
一旦达到所需的大小限制,我们只需要检查当前最小的项目。如果那个最小的项目比新项目小,它就会被替换。
为了测试update 代码,我创建了一个生成器datagen,它可以生成假数据。为了使输出易于管理,我将大小缩减为前 20 名列表,而不是前 50 名。
from random import seed, randint
from heapq import heappush, heapreplace
seed(42)
# Make some fake data, in this form: (power, x_pos, y_pos, z_pos)
def datagen():
m = (100., 1., 1., 1.)
while True:
yield tuple(randint(1, 100) * u for u in m)
top20 = {}
heap = []
# Update the heap & the dict
def update(k, tup):
if len(top20) < 20:
heappush(heap, tup + (k,))
top20[k] = tup
elif tup[0] > heap[0][0]:
old = heapreplace(heap, tup + (k,))
top20[k] = tup
del top20[old[-1]]
print('replaced', old[0])
# Test
for k, tup in zip(range(50), datagen()):
print(k, tup)
update(k, tup)
输出
0 (8200.0, 15.0, 4.0, 95.0)
1 (3600.0, 32.0, 29.0, 18.0)
2 (9500.0, 14.0, 87.0, 95.0)
3 (7000.0, 12.0, 76.0, 55.0)
4 (500.0, 4.0, 12.0, 28.0)
5 (3000.0, 65.0, 78.0, 4.0)
6 (7200.0, 26.0, 92.0, 84.0)
7 (9000.0, 70.0, 54.0, 29.0)
8 (5800.0, 76.0, 36.0, 1.0)
9 (9800.0, 21.0, 90.0, 55.0)
10 (4400.0, 36.0, 20.0, 28.0)
11 (9800.0, 44.0, 14.0, 12.0)
12 (4900.0, 13.0, 46.0, 45.0)
13 (7800.0, 34.0, 6.0, 94.0)
14 (5900.0, 69.0, 16.0, 49.0)
15 (1100.0, 71.0, 38.0, 81.0)
16 (8000.0, 47.0, 74.0, 25.0)
17 (9100.0, 9.0, 6.0, 85.0)
18 (3000.0, 99.0, 38.0, 11.0)
19 (3000.0, 13.0, 49.0, 36.0)
20 (5900.0, 82.0, 47.0, 21.0)
replaced 500.0
21 (4800.0, 46.0, 27.0, 86.0)
replaced 1100.0
22 (3500.0, 90.0, 88.0, 83.0)
replaced 3000.0
23 (1000.0, 78.0, 82.0, 22.0)
24 (6900.0, 94.0, 32.0, 21.0)
replaced 3000.0
25 (6000.0, 49.0, 35.0, 82.0)
replaced 3000.0
26 (8900.0, 72.0, 29.0, 88.0)
replaced 3500.0
27 (4200.0, 99.0, 100.0, 8.0)
replaced 3600.0
28 (3000.0, 5.0, 41.0, 52.0)
29 (3500.0, 9.0, 28.0, 73.0)
30 (9200.0, 41.0, 28.0, 84.0)
replaced 4200.0
31 (6400.0, 51.0, 83.0, 59.0)
replaced 4400.0
32 (1900.0, 34.0, 18.0, 32.0)
33 (9600.0, 72.0, 69.0, 34.0)
replaced 4800.0
34 (9600.0, 75.0, 55.0, 75.0)
replaced 4900.0
35 (5200.0, 47.0, 29.0, 18.0)
36 (6600.0, 64.0, 12.0, 97.0)
replaced 5800.0
37 (700.0, 15.0, 20.0, 81.0)
38 (2100.0, 88.0, 55.0, 77.0)
39 (900.0, 50.0, 49.0, 77.0)
40 (6000.0, 68.0, 33.0, 71.0)
replaced 5900.0
41 (200.0, 88.0, 93.0, 15.0)
42 (8800.0, 69.0, 97.0, 35.0)
replaced 5900.0
43 (9900.0, 83.0, 44.0, 15.0)
replaced 6000.0
44 (3800.0, 56.0, 21.0, 59.0)
45 (100.0, 93.0, 93.0, 34.0)
46 (6500.0, 98.0, 23.0, 65.0)
replaced 6000.0
47 (1400.0, 81.0, 39.0, 82.0)
48 (6500.0, 78.0, 26.0, 20.0)
replaced 6400.0
49 (4800.0, 98.0, 21.0, 70.0)
print('replaced', old[0]) 调用不是必需的,但它对于测试和调试很有用。