我正在寻找解决以下问题的最有效/蟒蛇方式:
我有一个本地对象列表(list_a
),一个服务器上的对象列表(list_b
)。 list_b
是字典列表,而不是对象。
我想用服务器给出的信息更新本地对象中的一些信息。可以通过字典中的属性name
或标识符'name'
来完成分配。两个列表都可以是彼此的子集。
以下是我当前的解决方案,其中包含一些示例数据:
class Dummy():
def __init__(self, name):
self._name = name
self._attr = ''
def __str__(self):
return "Test-Object[" + self._name + ", " + self._attr + "]"
def update(self, obj):
self._attr = obj['attr']
__repr__ = __str__
list_a = [Dummy(str(x)) for x in xrange(10)]
list_b = [{'name': str(x), 'attr': str(x*2)} for x in xrange(8, -1, -1)]
extracted_names_a = [x._name for x in list_a]
extracted_names_b = [x['name'] for x in list_b]
filtered_list_a = (x for x in list_a if x._name in extracted_names_b)
filtered_list_b = (x for x in list_b if x['name'] in extracted_names_a)
sorted_list_a = sorted(filtered_list_a, key=lambda k: k._name)
sorted_list_b = sorted(filtered_list_b, key=lambda k: k['name'])
for obj, d in zip(sorted_list_a, sorted_list_b):
obj.update(d)
print(list_a)
这只是一个简单的例子,在现实世界中有2000多个条目和更多的数据
答案 0 :(得分:1)
你最大的问题是过滤。对于每个列表的每个元素,您将搜索整个其他列表以查看它是否存在。这需要二次时间。如果将这些对象转换为名称组或由名称键控的dicts,则可以消除该二次函数并使其成为对数线性。
之后,sorted
也不再需要了,这是代码是对数线性的唯一原因,所以现在它是线性的。
当我们处于它的时候,你正在浪费内存,可能是时间,建立一个列表只是为了在下一行的生成器表达式中迭代它。如果我们摆脱sorted
,这就变得更加重要,因为那时我们永远不需要列表。
所以:
dict_a = {x._name: x for x in list_a}
for d in list_b:
try:
dict_a[d['name']].update(d)
except KeyError:
pass
使用try / except进行dict查找会在没有匹配对象的情况下过滤掉dicts,并且您不需要在没有匹配dicts的情况下过滤掉对象,因为它们不会被调用。
如果有更多的词组而不是对象,则反转词来制作词典的词典并迭代对象。
或者,如果您可以首先将对象保存在dict中,而不是将它们保留在列表中并为此代码创建临时dict,那就更好了。如果您在解析时逐个迭代dicts然后关闭服务器响应而不是首先构建它们的列表,那么您将消除所有不必要的大量分配,并可能进一步加快速度。
答案 1 :(得分:0)
不应将对象存储在列表中,而应将该列表转换为dict:
objects_by_name = {obj._name: obj for obj in list_a}
这使您可以在O(1)
时间内查找与名称关联的对象。
现在,更新所有对象就像迭代list_b
一样简单,从dict中获取相应的对象,并调用其update
方法:
for dic in list_b:
obj = objects_by_name[dic['name']]
obj.update(dic)
总体而言,时间复杂度为O(n)
,而您的代码为O(n log n)
,因为排序。