【问题标题】:Efficient way of assigning dicts to objects in Python在 Python 中将字典分配给对象的有效方法
【发布时间】:2018-04-09 23:35:44
【问题描述】:

我正在寻找解决以下问题的最有效/python 方法:

我有一个本地对象列表 (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 多个条目和更多的数据

【问题讨论】:

  • 仅供参考,我已将变量 dict 重命名为 d。不要在类之后命名变量。
  • 当你说高效/python方式时,究竟是什么意思...内存高效?速度?您是否对足够高效有一个门槛?基本上,这个问题的上下文是什么?
  • 所有 python 字典都有内置方法,称为 itemsiteritems 。您还可以使用关键字字典语法来实例化对象,例如Dummy(**myArgsDictionnary) (您需要在 init 参数中添加相应的属性)
  • @Yftach 我的解决方案似乎超载(对我而言),包含提取的列表、生成器和排序列表。我对python有点陌生,所以也许有一种更优雅的方法。目前最大的担忧是速度。
  • 这段代码真的只需要一小部分时间吗?例如,从服务器下载对象?您似乎正在尝试对可能不在瓶颈附近的代码进行微优化。

标签: python dictionary optimization lambda


【解决方案1】:

您最大的问题是过滤。对于每个列表的每个元素,您都在搜索整个另一个列表以查看它是否存在。这需要二次时间。如果将这些对象转换为名称集或按名称键入的字典,则可以消除二次工作并使其成为对数线性。

在那之后,sorted 也不再需要,这是代码是对数线性的唯一原因,所以现在它是线性的。

当我们这样做的时候,你在浪费内存,可能还浪费时间,建立一个列表只是为了在下一行的生成器表达式中迭代它。如果我们摆脱@​​987654322@,这将变得更加重要,因为这样我们就永远需要一个列表。

所以:

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 的对象,因为它们不会被调用。

如果字典比对象多得多,则反转事物以制作字典的字典并遍历对象。

或者,如果您可以首先将对象保存在字典中,而不是将它们保存在列表中并仅为此代码制作临时字典,那就更好了。如果您可以在解析时逐个迭代字典,然后关闭服务器响应,而不是首先构建它们的列表,您将消除所有不必要的大分配,并可能进一步加快处理速度。

【讨论】:

    【解决方案2】:

    您应该将该列表转换为字典,而不是将对象存储在列表中:

    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) 因为排序。

    【讨论】:

      猜你喜欢
      • 2020-12-24
      • 1970-01-01
      • 2018-04-24
      • 2013-05-11
      • 2017-07-13
      • 2020-12-21
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      相关资源
      最近更新 更多