Python:更新元组列表。。。最快方法

Python:更新元组列表。。。最快方法,python,Python,此问题与此处提出的另一个问题相关: 从那时起,我就发现了我在分类方面遇到的问题。每次更新数据时,我都会将字典中的条目排序到一个列表中。我后来意识到,Python排序的强大之处在于它能够更快地对已经部分排序的数据进行排序 所以,问题来了。假设我有以下示例集: self.sorted_records = [(1, 1234567890), (20, 1245678903), (40, 1256789034), (70, 1278903456)] 列

此问题与此处提出的另一个问题相关:

从那时起,我就发现了我在分类方面遇到的问题。每次更新数据时,我都会将字典中的条目排序到一个列表中。我后来意识到,Python排序的强大之处在于它能够更快地对已经部分排序的数据进行排序

所以,问题来了。假设我有以下示例集:

self.sorted_records = [(1, 1234567890), (20, 1245678903), 
                       (40, 1256789034), (70, 1278903456)]
列表中每个元组的
t[1]
都是唯一的id。现在我想用以下内容更新此列表:

updated_records = {1245678903:45, 1278903456:76}
对我来说,最快的方法是什么

self.sorted_records = [(1, 1234567890), (45, 1245678903),
                       (40, 1256789034), (76, 1278903456)]
目前我正在做这样的事情:

updated_keys = updated_records.keys()
for i, record in enumerate(self.sorted_data):
    if record[1] in updated_keys:
        updated_keys.remove(record[1])
        self.sorted_data[i] = (updated_records[record[1]], record[1])
但我相信有一个更快、更优雅的解决方案

有什么帮助吗

*编辑 事实证明,我对ID使用了不好的示例,因为当我进行更新时,它们以排序的顺序结束。我实际上对t[0]的排序很感兴趣。在我做了更新之后,我打算使用更新的数据,但看起来对分可能是按排序顺序插入的票证。
结束编辑*

您正在扫描所有n条记录。您可以改为执行二进制搜索,这将是O(log(n))而不是O(n)。您可以使用模块执行此操作。

您正在扫描所有n条记录。您可以改为执行二进制搜索,这将是O(log(n))而不是O(n)。您可以使用该模块来完成此操作。

因为您显然不关心实际被排序的
self.sorted\u记录的结束值(您的值的顺序为1、45、20、76——这不是排序的!-),而且您似乎只关心
更新的\u记录中的ID,这些记录也在
self.sorted\u data
列表中(如果您想在飞行中更改更新的_记录,则会产生副作用)将为您提供良好的服务,即:

self.sorted_data = [(updated_records.pop(recid, value), recid) 
                    for (value, recid) in self.sorted_data]
.pop
调用将从
更新的\u记录中删除在新的
自排序\u数据中结束的键(和相应的值)
(以及“该
recid的先前值”),作为pop的第二个参数提供,
value
,以确保recid不在
updated\u record
)中时不会发生更改;这将在
updated\u record
中留下“新”内容,以便您可以在重新排序之前将其附加到
self.sorted\u data
,即我怀疑您想继续执行类似的操作

self.sorted_data.extend(value, recid 
                        for recid, value in updated_records.iteritems())
self.sorted_data.sort()

虽然这一部分确实超出了您实际提出的问题(我给出这一部分只是因为我看到了您之前的问题;-)。

因为显然您不关心
self.sorted\u记录的结束值实际被排序(您的值顺序为1、45、20、76,这不是排序的!),并且您似乎只关心
更新的\u记录中的ID,而这些记录也在
self中。排序的\u数据
,listcomp(如果您想动态更改更新的\u记录,则会产生副作用)会很好地为您服务,即:

self.sorted_data = [(updated_records.pop(recid, value), recid) 
                    for (value, recid) in self.sorted_data]
.pop
调用将从
更新的\u记录中删除在新的
自排序\u数据中结束的键(和相应的值)
(以及“该
recid的先前值”),作为pop的第二个参数提供,
value
,以确保recid不在
updated\u record
)中时不会发生更改;这将在
updated\u record
中留下“新”内容,以便您可以在重新排序之前将其附加到
self.sorted\u data
,即我怀疑您想继续执行类似的操作

self.sorted_data.extend(value, recid 
                        for recid, value in updated_records.iteritems())
self.sorted_data.sort()

虽然这一部分确实超出了您实际提出的问题(我给出这一部分只是因为我看到了您之前的问题;-).

由于您希望替换为字典键,但数组按字典值排序,因此您肯定需要对键进行线性搜索。从这个意义上说,您的算法是您所希望的最佳算法


如果您想保留旧的字典值,那么您可以使用二进制搜索值,然后在二进制搜索引导您的位置附近定位键。

由于您希望替换为字典键,但数组按字典值排序,因此您肯定需要对键进行线性搜索。从这个意义上说,您的alg算法是你所能期望的最好的


如果您想保留旧的字典值,那么您可以使用二进制搜索来查找该值,然后在二进制搜索引导您的位置附近找到键。

这里最好使用某种形式的树(保留排序顺序,同时允许O(log n)替换)没有内置的平衡树类型,但您可以找到许多第三方示例。或者,您可以:

  • 使用二进制搜索查找节点。对分模块将执行此操作,但它会根据正常的python比较顺序进行比较,而您似乎是根据每个元组的第二个元素进行排序。您可以反转此操作,或者只编写自己的二进制搜索(或者只需从对分_左侧获取代码并修改它)

  • 同时使用dict列表。该列表仅包含已排序的。您可以轻松包装dict类,以确保保持同步。这允许您在保持键的排序顺序的同时快速更新dict。这将防止由于不断转换而丢失排序性能的问题n在dict/list之间

  • 下面是这样一个东西的快速实现:

    import bisect
    
    class SortedDict(dict):
        """Dictionary which is iterable in sorted order.
    
        O(n) sorted iteration
        O(1) lookup
        O(log n) replacement  ( but O(n) insertion or new items)
        """
    
        def __init__(self, *args, **kwargs):
            dict.__init__(self, *args, **kwargs)
            self._keys = sorted(dict.iterkeys(self))
    
        def __setitem__(self, key, val):
            if key not in self:
                # New key - need to add to list of keys.
                pos = bisect.bisect_left(self._keys, key)
                self._keys.insert(pos, key)
            dict.__setitem__(self, key, val)
    
        def __delitem__(self, key):
            if key in self:
                pos = bisect.bisect_left(self._keys, key)
                del self._keys[pos]
            dict.__delitem__(self, key)
    
        def __iter__(self):
            for k in self._keys: yield k
        iterkeys = __iter__
    
        def iteritems(self):
            for k in self._keys: yield (k, self[k])
    
        def itervalues(self):
            for k in self._keys: yield self[k]
    
        def update(self, other):
            dict.update(self, other)
            self._keys = sorted(dict.iterkeys(self)) # Rebuild (faster if lots of changes made - may be slower if only minor changes to large dict)
    
        def keys(self): return list(self.iterkeys())
        def values(self): return list(self.itervalues())
        def items(self): return list(self.iteritems())
    
        def __repr__(self):
            return "%s(%s)" % (self.__class__.__name__, ', '.join("%s=%r" % (k, self[k]) for k in self))
    

    这里最好使用某种形式的树(保留排序顺序,同时允许O(logn)替换)。没有内置的平衡树类型,但您可以找到许多第三方示例。或者,您可以:

  • 使用二进制搜索查找节点。对分模块将执行此操作,但它会根据正常的python比较顺序进行比较,而您似乎是根据每个元组的第二个元素进行排序