考虑采用Pythonic方法。正如Ed Post所说,“决心的真正程序员可以使用任何语言编写FORTRAN程序”,这是普遍适用的... 如果你试图在Python中编写C代码,但效果不佳:-)
相反,考虑在
list
旁边放置一个辅助的
dict
缓存——缓存找到项的索引(只需要在列表结构进行“深度”更改时失效)。这样做更简单
而且更快...
最好通过创建一个小类来实现
list
和
dict
。
class Seeker(object):
def __init__(self, *a, **k):
self.l = list(*a, **k)
self.d = {}
def find(self, value):
where = self.d.get(value)
if where is None:
self.d[value] = where = self.l.find(value)
return where
def __setitem__(self, index, value):
if value in self.d: del self.d[value]
self.l[index] = value
def __getattr__(self, name):
return getattr(self.l, name)
你只需要定义你实际需要使用的变异器,例如,如果你不会执行插入、排序、__delitem__等操作,则无需定义这些操作,你可以将它们委托给列表。
补充:在Python 3.2或更高版本中,functools.lru_cache实际上可以为您完成大部分工作——用它来装饰查找函数,您将获得一个更好的缓存实现,如果需要,还可以限制缓存大小。要清除缓存,您需要在适当的位置调用self.find.cache_clear()(我在上面使用self.d = {})——不幸的是,这个关键功能尚未(尚未!-)记录在文档中(更新文档的志愿者与更新代码的人不是同一个人...!-)......但是,请相信我,它不会消失在你眼前:-)。
补充:OP编辑了Q以澄清他不追求“值相等”,而是一些更复杂的条件集,例如由谓词表示的条件集。
def good_for_g(g, n):
# for some container `g` and item value `n`:
u, v, w = n.value
return v in g[u] and w in g[v] and u not in g[w]
据推测,把“好”的项目排到前面的愿望基于它们的“好处”是“粘性”的前提,即
g
在一段时间内基本保持不变。在这种情况下,可以使用谓词作为特征提取和检查函数,形成字典的关键字--例如:
class FancySeeker(object):
def __init__(self, *a, **k):
self.l = list(*a, **k)
self.d = {}
def _find_in_list(self, predicate):
for i, n in enumerate(self.l):
if predicate(n):
return i
return -1
def find(self, predicate):
where = self.d.get(predicate)
if where is None:
where = self._find_in_list(predicate)
self.d[predicate] = where
return where
等等其他的。
因此,剩下的困难是将 predicate
放到适合有效索引到 dict
中的形式中。如果 predicate
只是一个函数,那就没有问题。但是,如果 predicate
是一个带有参数的函数,例如通过 functools.partial
形成或作为某个实例的绑定方法,这就需要进一步处理/包装才能使索引工作。
例如,对同一个绑定参数和函数进行两次调用 functools.partial
不会返回相等的对象——必须检查返回对象的 .args
和 .func
,以确保对于任何给定的 (func, args)
对,都返回一个“单例”。
此外,如果一些绑定参数是可变的,那么需要使用它们的
id
代替它们的
hash
(否则原始的
functools.partial
对象将无法哈希)。对于绑定方法来说,情况甚至更加复杂,但它们可以类似地包装成可哈希的“相等调整”的
Predicate
类。
最后,如果这些操作过于繁琐,并且您真的想使用快速实现的链表,请查看
https://pypi.python.org/pypi/llist/0.4 - 它是 Python 的单向和双向链表的 C 编码实现(对于每种类型,它都实现了三种类型:列表本身、列表节点和列表的迭代器)。
find()
(或in
)。如果那么容易,我首先会使用set
。我编辑了我的问题来指出这一点。抱歉。 - R2-D2