提高数据比较性能

时间:2017-08-10 23:50:44

标签: python

如何提高以下代码的性能?

self.adverts = set() # Around 11k rows
self.old_adverts= set() # Around 11k rows
self.advs = []

...

# Find modified items
for item in self.new_items:
   for old_item in self.old_items:
       if item.id == old_item.id and item.price != old_item.price:
          self.advs.append(
                    {
                    'delete': old_item,
                    'new': item,
                    'archive': old_item
                    }
          )

Item上课:

class Item(Base):
   ...

   id = Column(String(25), nullable=False, primary_key=True)
   price = Column(Numeric(precision=8), nullable=False, primary_key=True)

   # Another multiple additional fields
   ...

   def __eq__(self, other):
       return self.id == other.id

   def __hash__(self):
       return hash(self.id)

以上数据比较需要太多时间。我不知道如何禁食它。

UPD: 但是,下面我设法改进了另一段代码的性能:

# for item in self.items:
#   if item not in self.old_items:
#       self.insert_items_db.add({'new': item})

# Find absolutely new items
for new_item in self.items- self.old_items:
    self.advs.append({'new': new_item})

对象已预定义__eq____hash__个功能:

def __eq__(self, other):
    return self.id == other.id

def __hash__(self):
    return hash(self.id)

2 个答案:

答案 0 :(得分:1)

我没有完全遵循您的代码,但您可以通过使用字典来加快比较两个列表。这是O(n)而不是O(n ^ 2),因为检查存在从O(n)减少到O(1)。

例如。假设你有一堆带有变量id,value,color的对象。

for x in list1:       #N operations
    for y in list2:   #N operations
        if x.id == y.id:  #O(1)
            #do stuff

相反,你可以这样做:

#create two dictionaries where each key is the ID and each value is the
#object, data, other things etc.
dict1 = { x.id:x for x in list1}   
dict2 = { y.id:y for y in list2}   

现在您的代码变为:

for x in dict1.keys():     #O(N)
    if x in dict2:         #O(1)
         #Do some stuff

现在是O(n)时间。

现在,如果你想比较价格,那就变得棘手了。如果我们有多个Id元素(例如,同一组中存在冲突)那么我们可以将字典中的每个条目转换为对象列表。这在理论上仍然是O(N ^ 2)运算,但它比通过所有11k元素的迭代有很大的改进。

我们假设没有重复的Ids。然后代码变为:

for x in dict1.keys():     #O(N)
    if x in dict2:         #O(1)
        if dict1[x].price != dict2[x].price:  #or any other comparison
             #do stuff

如果有重复的ID,那么字典结构应该如下所示:

my_dict = {\
    1001: [ obj1, obj2, obj3]\  #where obj1.id == obj2.id == obj3.id
    1002: [obj4, obj5, obj6]\   #where obj4.id == obj5.id == obj6.id
    }

代码适用于反映以下内容

for x in dict1.keys():     
    if x in dict2:   
        if x in dict2:
            for my_object_type in dict2[x]:     #something about this seems familiar.....
                if x.other_identifier == my_object_type.other_identifer:
                #finally do some stuff!

这是最疯狂的部分!

在上面的代码中,我添加了另一个for循环。这又是O(N)速度,这就是代码再次降低到O(N ^ 2)的原因。但是,如果我们有另一个标识符,例如“Id2”或“color_of_left_toe”,那么我们可以创建另一个字典!!

此时,结构将演变成对象字典的字典。相当复杂,但!!访问时间可以保持为O(1)!

为什么“在dict中”更快?

在第一个代码示例中,您将遍历第一个列表,然后再次遍历另一个列表。

因此,对于list1中的第一个元素,您将遍历len(list2)或 N

因为你正在为X中的每个元素循环遍历这个循环,你正在做 N 次。

N + N + N + N ............ N

\ ~~~~~~ N次 ~~~~~~ /

或O(N ^ 2)

现在为什么dict更快?

字典散列每个元素,然后根据此散列存储它。这意味着您无需查看复杂的二叉树或数组来查找所需内容。相反,你会做一些O(1)时间数学计算,你需要根据你给它的关键点立即检查。

答案 1 :(得分:0)

这很大程度上取决于你做什么"做什么"需要。如果这是一个简单的记录更新,那么忘记这个set实现并去找一本字典。使用旧数据创建旧字典,键入产品ID。然后用新数据更新它。

catalog =       {self.id: [ <remainder of the row> ] for self in old_data}
catalog.update( {self.id: [ <remainder of the row> ] for self in new_data} )