我有一个dicts列表,如下所示:
test_data = [
{ 'offset':0, 'data':1500 },
{ 'offset':1270, 'data':120 },
{ 'offset':2117, 'data':30 },
{ 'offset':4055, 'data':30000 },
]
dict项目根据'offset'
数据在列表中排序。真实数据可能会更长。
我想要做的是在给定特定偏移值的列表中查找项目,不恰好是其中一个值,但在该范围内。所以,我想做的就是二元搜索。
我现在知道Python bisect
模块,它是一个现成的二进制搜索 - 很好,但不能直接用于这种情况。我只是想知道根据我的需求调整bisect
的最简单方法是什么。以下是我提出的建议:
import bisect
class dict_list_index_get_member(object):
def __init__(self, dict_list, member):
self.dict_list = dict_list
self.member = member
def __getitem__(self, index):
return self.dict_list[index][self.member]
def __len__(self):
return self.dict_list.__len__()
test_data_index_get_offset = dict_list_index_get_member(test_data, 'offset')
print bisect.bisect(test_data_index_get_offset, 1900)
打印:
2
我的问题是,这是做我想做的最好的方法,还是有其他更简单,更好的方式?
答案 0 :(得分:6)
您还可以使用Python的许多SortedDict实现之一来管理您的test_data。已排序的dict按键对元素进行排序,并维护到值的映射。某些实现还支持对键进行二等分操作。例如,Python sortedcontainers module的SortedDict符合您的要求。
在你的情况下,它看起来像:
from sortedcontainers import SortedDict
offset_map = SortedDict((item['offset'], item['data']) for item in test_data)
index = offset_map.bisect(1275)
key = offset_map.iloc[index]
print offset_map[key]
# 120
SortedDict类型具有bisect函数,该函数返回所需键的二分索引。使用该索引,您可以查找实际密钥。使用该密钥,您可以获得价值。
所有这些操作在sortedcontainers中都非常快,也可以用纯Python实现。还有一个performance comparison,它讨论了其他选择,并有基准数据。
答案 1 :(得分:4)
当你说真实数据可能会更长时,是否会阻止你手头保留一个偏移值列表?
offset_values = [i['offset'] for i in test_data]
bisect.bisect(offset_values, 1900)
你的方法对我来说似乎很好。
答案 2 :(得分:4)
你能做的就是这个
class OffsetWithAttributes( object ):
def __init__( self, offset, **kw ):
self.offset= offset
self.attributes= kw
def __eq__( self, other ):
return self.offset == other.offset
def __lt__( self, other ):
return self.offset < other.offset
def __le__( self, other ):
return self.offset <= other.offset
def __gt__( self, other ):
return self.offset > other.offset
def __ge__( self, other ):
return self.offset >= other.offset
def __ne__( self, other ):
return self.offset != other.offset
这应该允许您创建一个简单的list
OffsetWithAttributes
个实例。 bisect
算法应该非常乐意使用已定义的运算符。
您可以使用someOWA.attributes['data']
。
或者
def __getattr__( self, key ):
return self.attributes[key]
这应该使OffsetWithAttributes
更像dict
。
答案 3 :(得分:3)
这里的常用模式类似于按属性排序,装饰,操作和未装饰。所以在这种情况下你只需要装饰然后再打电话。但是你要避免这样做,因为decorate将是O(n),而你希望它是O(logn)。因此,我认为你的方法最好。
答案 4 :(得分:0)
如果可以的话,元组可以使用bisect ...
import bisect
offset = 0
data = 1
test_data = [
(0, 1500),
(1270, 120),
(2117, 30),
(4055, 30000),
]
i = bisect.bisect(test_data, (1900,0))
test_data.insert(i, (1900,0))
print(test_data[i][data])
尽管由于元组被“按字典顺序”比较(从左到右),直到一个元素不等于另一个元素-您必须考虑这是否是所需的行为
>>> bisect.insort(test_data, (2117,29))
>>> print(test_data)
[(0, 1500), (1270, 120), (2117, 29), (2117, 30), (4055, 30000)]