从按时间排序的列表中删除旧元素

时间:2016-01-21 09:42:03

标签: python performance list

假设我有一个列表l,其中每个元素都有一个属性time,它存储一个浮点数,表示从某个基准点过去的秒数。每当发生某些事件时,我想从此列表中删除在此事件发生前超过T秒发生的所有元素,因此目前我所做的是

l = [x in l if x.time > current_time - T]

这似乎是一种缓慢的做事方式。怎么能更快地完成?元素按时间排序,所以我想找到第一个不满足这个条件的元素,例如:

for i, x in enumerate(l):
    if x.time > current_time - T:
         break
l = l[i:]

也许有一种更好的方式?

3 个答案:

答案 0 :(得分:0)

您可以使用deque中的collections。它为您提供了O(1)复杂性,可以从列表的头部删除元素。由于元素按时间排序,而最旧的元素位于列表的开头,因此您可以轻松地逐个删除元素。

答案 1 :(得分:0)

由于它们是按时间排序的,因此您可以使用二进制搜索来查找截止点的索引,然后重新切片列表。二进制搜索应该(大致)找到截止点时的O(log n),然后是切片的O(n)。

但是,如果你经常这样做,最好使用双端队列并简单地弹出元素,直到头部“在要保持的时间内”。

所以无论什么是最好的都需要基准测试。但是,deque解决方案(可能)更容易编写,因此最好从那里开始,然后在遇到性能问题时考虑其他方法。

答案 2 :(得分:0)

import random

class Element():

    def __init__(self, time):
        self.time = time

l = [ Element(z*5 - random.randrange(6) + 3) for z in range( 21)]
print('list:', [z.time for z in l])
target_time = 72
print('cutoff time:', target_time)


match = False
working_list_from = 0
working_list_to = len(l)
while not match:
    mid = (working_list_to - working_list_from) // 2
    if l[working_list_from + mid].time < target_time:
        working_list_from += mid
    else:
        working_list_to -= mid


    match = (working_list_to - working_list_from) == 1

print(' resulting list', [z.time for z in l[working_list_from+mid:]])

结果:

list: [3, 5, 9, 18, 21, 25, 32, 33, 40, 48, 49, 57, 62, 67, 73, 73, 79, 85, 93, 94, 99]
cutoff time: 72
 resulting list [73, 73, 79, 85, 93, 94, 99]