代码之家  ›  专栏  ›  技术社区  ›  Matina G

检查具有不同属性的对象的相等性

  •  3
  • Matina G  · 技术社区  · 7 年前

    我有两个对象列表,我需要根据两组不同的属性找到匹配的对象。比方说,我有Vehicle()对象,我需要首先匹配第一个列表中与第二个列表中的车辆相等的所有车辆,首先查看匹配的颜色,然后查看匹配的品牌。 我有两个解决方案,但我不确定这是否是我能做的最好的。(我真的需要优化这个性能)

    class Vehicle(object):
        def __init__(self, color, brand):
            self._color = color
            self._brand = brand
    

    以及对象列表:

    vehicles1= [Vehicle('blue','fiat'), Vehicle('red','volvo'), Vehicle('red','fiat')]
    
    vehicles2 = [Vehicle('blue', 'volvo'), Vehicle('red', 'BMW')]
    

    第一个解决方案似乎慢得离谱,它只能通过列表包含来工作:

    inersect_brand_wise = [x for x in vehicles1 for y in vehicles2 if x._brand == y._brand] 
    

    然后

     intersect_color_wise = [x for x in vehicles1 for y in vehicles2 if x._color == y._color]
    

    我提出的第二个解决方案是阐述平等:

    class Vehicle(object):
        def __init__(self, color, brand):
            self._color = color
            self._brand = brand
    
        def __eq__(self, other):
            if isinstance(other, Vehicle):
                return self._brand == other._brand
            return False
        def __hash__(self):
            return hash((self._color, self._brand))
    

    现在,获得交叉路口品牌智慧是微不足道的:

    inersect_brand_wise = [x for x in vehicles1 if x in vehicles2]
    

    为了获得交叉点颜色,我做了以下工作:

    class Car(Vehicle):
        def __init__(self, color, brand):
            Vehicle.__init__(self,color, brand)
    
    
    def __hash__(self):
        return Vehicle.__hash__
    
    def __eq__(self, other):
        if isinstance(other, Car):
            return other._color == self._color
        return False
    
    
    def change_to_car(obj):
        obj.__class__ = Car
        return obj
    
    
    cars1 = map(change_to_car, vehicles1)
    cars2  = map(change_to_car, vehicles2)
    

    因此,

    intersect_color_wise = [x for x in cars1 if x in cars2]
    

    给出第二个十字路口。

    然而,在我看来,这是一个非常笨拙的方式来做事情,我实际上需要在这一个良好的表现。

    关于如何做得更好有什么建议吗?

    4 回复  |  直到 7 年前
        1
  •  0
  •   r.ook jpp    7 年前

    在这种情况下表现如何?没有完整的数据集来模拟性能以进行适当的测试…:

    def get_intersections(list1, list2):
        brands, colors = map(set, zip(*[(v._brand, v._color) for v in list2]))
        inter_brands = [v for v in list1 if v._brand in brands]
        inter_colors = [v for v in list1 if v._colors in colors]
        return inter_brands, inter_colors
    

    如果需要,还可以编写单个交点:

    from operator import attrgetter
    
    def get_intersection(list1, list2, attr:str):
        getter = attrgetter(attr)
        t_set = {getter(v) for v in list2}
        results = [v for v in list1 if getter(v) in t_set]
        return results
    
    # use it like this:
    get_intersection(vehicles1, vehicles2, "_brand")
    

    也可以使用 attrgetter

    def get_intersections(list1, list2, *attrs:str):
        getter = attrgetter(*attrs)
        if len(attrs) > 1:
            sets = list(map(set, zip(*[getter(v) for v in list2])))
        else:
            sets = [{getter(v) for v in list2}]
        results = {attr: [v for v in vehicles1 if getattr(v, attr) in sets[s]] for s, attr in enumerate(attrs)}
        return results
    

    测试:

    >>> get_intersections(vehicles1, vehicles2, "_brand", "_color")
    
    {'_brand': [<__main__.Vehicle object at 0x03588910>], '_color': [<__main__.Vehicle object at 0x035889D0>, <__main__.Vehicle object at 0x03588910>, <__main__.Vehicle object at 0x035889F0>]}
    
    >>> get_intersections(vehicles1, vehicles2, "_brand")
    
    {'_brand': [<__main__.Vehicle object at 0x03588910>]}
    
        2
  •  0
  •   Serge Ballesta    7 年前

    实际上Python是一种动态语言。那意味着你可以用猴子修补 Vehicle 随意上课,使之适合你的需要。您准备了另外两个类(我将它们设置为Vehicle的子类,以便autocompletion在IDE中工作)分别具有brand equality和color equality,并将它们的成员分配给Vehicle类:

    class Vehicle(object):
        def __init__(self, color, brand):
            self._color = color
            self._brand = brand
    
    class Vehicle_brand(Vehicle):
        def __eq__(self, other):
            return self._brand == other._brand
        def __hash__(self):
            return hash(self._brand)
    
    
    class Vehicle_color(Vehicle):
        def __eq__(self, other):
            return self._color == other._color
        def __hash__(self):
            return hash(self._color)
    

    要获得品牌交集:

    Vehicle.__eq__ = Vehicle_brand.__eq__
    Vehicle.__hash__ = Vehicle_brand.__hash__
    intersect_brand_wise = [x for x in vehicles1 if x in vehicles2]
    

    然后获得颜色交集:

    Vehicle.__eq__ = Vehicle_color.__eq__
    Vehicle.__hash__ = Vehicle_color.__hash__
    intersect_color_wise = [x for x in vehicles1 if x in vehicles2]
    

    好消息是,如果你 车辆 类有其他成员,当您更改相等部分时,它们保持不变,并且您从不复制任何对象:类对象中只有2个方法。

    它可能不是很纯,但它应该工作。。。

        3
  •  0
  •   stovfl    7 年前

    问题:检查具有不同属性的对象的相等性

    而是去寻找 平等的 然后,做 loop in loop ,检查 在实例化时。
    保存 memory ,仅保存 平等的

    • 使用 class attributs 举行会议 dict objects set 1
      和一个 list 举行会议 _hash 属于 平等的 物体 .

      class VehicleDiff:
          ref1 = {}
          _intersection = []
      
          def __init__(self, set, color, brand):
              self.color = color
              self.brand = brand
      
    • 保存的引用 第1组 中的对象 dict ref1 .
      只有 对象来自 set 2 反对 参考文献1 仅在相等时保存 .

              _hash = hash((color, brand))
              if set == 1:
                  VehicleDiff.ref1[_hash] = self
      
              elif _hash in VehicleDiff.ref1:
                  VehicleDiff._intersection.append(_hash)
      
    • 帮手 methode intersection 得到一个 VehicleDiff _散列 .

          @staticmethod
          def intersection():
              print('intersection:{}'.format(VehicleDiff._intersection))
              for _hash in VehicleDiff._intersection:
                  yield VehicleDiff.ref1[_hash]
      
    • 字符串的表示形式 车辆驾驶员 对象。

          def __str__(self):
              return 'color:{}, brand:{}'.format(self.color, self.brand)
      
    • 把物体固定在 .

      注意 :由于给定的示例数据没有交集,我添加了 ('red', 'fiat') 设置2

      for p in [('blue', 'fiat'), ('red', 'volvo'), ('red', 'fiat')]:
          VehicleDiff(1, *p)
      
      for p in [('blue', 'volvo'), ('red', 'BMW'), ('red', 'fiat')]:
          VehicleDiff(2, *p)
      
    • 打印结果, 如果有的话 .

      for vehicle in VehicleDiff.intersection():
          print('vehicle:{}'.format(vehicle))
      

    输出 :

    intersection:[2125945310]
    vehicle:color:red, brand:fiat
    

    用Python测试:3.4.2