Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 具有快速查找、快速更新和易于比较/排序的理想数据结构_Python_Data Structures - Fatal编程技术网

Python 具有快速查找、快速更新和易于比较/排序的理想数据结构

Python 具有快速查找、快速更新和易于比较/排序的理想数据结构,python,data-structures,Python,Data Structures,我正在寻找一个好的数据结构来包含一个具有(哈希,时间戳)值的元组列表。基本上,我想用以下方式使用它: 数据进来后,检查它是否已经存在于数据结构中(哈希相等,而不是时间戳) 如果是,则将时间戳更新为“现在” 如果没有,则将其添加到带有时间戳“now”的集合中 我希望定期删除并返回比特定时间戳早的元组列表(当它们“过期”时,我需要更新各种其他元素)。时间戳不必是任何特定的(它可以是unix时间戳、pythondatetime对象或其他易于比较的哈希/字符串) 我使用它来接收传入数据,如果数据已经

我正在寻找一个好的数据结构来包含一个具有
(哈希,时间戳)
值的元组列表。基本上,我想用以下方式使用它:

  • 数据进来后,检查它是否已经存在于数据结构中(哈希相等,而不是时间戳)
  • 如果是,则将时间戳更新为“现在”
  • 如果没有,则将其添加到带有时间戳“now”的集合中
我希望定期删除并返回比特定时间戳早的元组列表(当它们“过期”时,我需要更新各种其他元素)。时间戳不必是任何特定的(它可以是unix时间戳、python
datetime
对象或其他易于比较的哈希/字符串)

我使用它来接收传入数据,如果数据已经存在则进行更新,并清除超过X秒/分钟的数据

多个数据结构也可以是一个有效的建议(我最初使用的是优先级队列+集合,但是优先级队列对于不断更新值来说不是最佳的)


实现同样目标的其他方法也受到欢迎。最终目标是跟踪元素a)系统中的新元素、b)系统中已经存在的元素以及c)元素过期的时间。

如果您可以解决偶尔出现的误报问题,我认为bloom过滤器可能会很好地满足您的需要(非常快)

以及python实现:


编辑:再次阅读您的帖子,我认为这会起作用,但与其存储哈希,不如让bloomfilter为您创建哈希。我想你只是想用bloomfilter作为一组时间戳。我假设您的时间戳基本上可以是一个集合,因为您正在对它们进行哈希运算。

对于检查/更新/集合操作,一个简单的哈希表或字典将是O(1)。您可以同时将数据存储在一个简单的时间顺序列表中,用于清除操作。保留一个头和尾指针,这样insert也是O(1),删除操作非常简单,只需将头推进到目标时间,然后从散列中删除找到的所有条目

开销是每个存储的数据项增加一个指针,代码非常简单:

insert(key,time,data):
  existing = MyDictionary.find(key)
  if existing:  
      existing.mark()
  node = MyNodeType(data,time)  #simple container holding args + 'next' pointer
  node.next = NULL
  MyDictionary.insert(key,node)
  Tail.next = node
  if Head is NULL:  Head = node

clean(olderThan):
  while Head.time < olderThan:
    n = Head.next 
    if not Head.isMarked():  
        MyDictionary.remove(Head.key)
    #else it was already overwritten
    if Head == Tail: Tail = n
    Head = n
插入(键、时间、数据):
现有=MyDictionary.find(键)
如有:
现有的.mark()
node=MyNodeType(数据、时间)#包含args+下一个指针的简单容器
node.next=NULL
MyDictionary.insert(键,节点)
Tail.next=节点
如果Head为空:Head=节点
清洁(旧的):
当Head.time
我能想到的最接近具有所需属性的单个结构的是一个splay树(散列作为键)

通过将最近访问(因此更新)的节点旋转到根节点,您应该在叶节点处或在右侧子树中分组最近访问(因此更新)最少的数据

找出细节(并实现它们)留给读者作为练习


注意事项:

  • 最坏情况下的高度——因此复杂性——是线性的。这不应该与一个像样的散列一起发生
  • 任何只读操作(即,不更新时间戳的查找)都将破坏splay树布局和时间戳之间的关系

一种更简单的方法是将包含
(hash,timestamp,prev,next)
的对象存储在常规dict中,使用
prev
next
保持最新的双链接列表。那么,除了dict之外,您所需要的就是
head
tail
引用


插入和更新仍然是固定时间(散列查找+链表拼接),从列表尾部向后走收集最旧的散列是线性的。

除非我误读了你的问题,否则一个普通的旧
dict
应该适合除清除之外的所有操作。假设您试图避免在清除过程中检查整个字典,我建议保留第二个数据结构来保存
(时间戳、哈希)

此补充数据结构可以是普通的
列表
deque
(来自
集合
模块)。可能,
bisect
模块可以方便地将时间戳比较的次数降到最低(而不是将所有时间戳进行比较,直到达到截止值),但是由于您仍然需要按顺序迭代需要清除的项,熨烫出最快的确切细节需要一些测试

编辑:


< Python 2.7或3.1 +,您也可以考虑使用<代码> OrdEddit < /C> >(从<代码>集合>代码>模块。这基本上是一个
dict
,在类中内置了一个保留顺序的补充数据结构,因此您不必自己实现它。唯一的问题是它保留的唯一顺序是插入顺序,因此,出于您的目的,您需要删除它(使用
del
),然后使用新的时间戳分配新的条目,而不是将现有条目重新分配给新的时间戳。尽管如此,它仍然保留了O(1)查找,并使您不必自己维护
(时间戳,散列)
对的列表;当需要清除时,您可以直接迭代通过
OrderedDict
,删除条目,直到到达一个时间戳晚于截止日期的条目。

这是一个非常好的空间。您需要的是两个结构,您需要一些东西来告诉您集合是否知道您的密钥(
hash
)。对于这一点,
dict
非常适合;我们将把
散列映射到
import heapq


class ExpiringCache(object):
    def __init__(self):
        self._dict = {}
        self._heap = []

    def add(self, key, expiry):
        self._dict[key] = expiry
        heapq.heappush(self._heap, (expiry, key))

    def contains(self, key):
        return key in self._dict

    def collect(self, maxage):
        while self._heap and self._heap[0][0] <= maxage:
            expiry, key = heapq.heappop(self._heap)
            if self._dict.get(key) == expiry:
                del self._dict[key]

    def items(self):
        return self._dict.items()
>>> xc = ExpiringCache()
>>> xc.add('apples', 1)
>>> xc.add('bananas', 2)
>>> xc.add('mangoes', 3)
>>> xc.add('apples', 4)
>>> xc.collect(2)    
>>> xc.contains('apples')
True
>>> xc.contains('bananas')
False