【问题标题】:Add class attributes if another class attribute match the other in a list如果另一个类属性与列表中的另一个匹配,则添加类属性
【发布时间】:2017-04-17 21:21:54
【问题描述】:

我有这样的课程:

class ex(object):

    def __init__(self, tag, quantity):
        self.tag = tag
        self.quantity = quantity

我还有一个包含此类多个实例的列表,例如:

[ex('a', 10.5), ex('b', 5.0),  ex('c', 2.0), ex('a', 5.0), ex('c', -10.0)]

如果 self.tag 与列表中的另一个实例匹配,我正在尝试找出一种添加 self.quantiy 属性的好方法。

输出将是:

[ex('a', 15.5), ex('b', 5.0),  ex('c', -8.0)]

谢谢

edit:最终实例可以是一个新实例,也可以是累积的列表中的第一个。列表的最大大小将在 len() 的 1000 左右

【问题讨论】:

  • 您要创建新实例还是修改现有实例?
  • 这个列表可能有多大? O(n^2) 解决方案是否可以接受?
  • 两种方式都行,我更喜欢新实例
  • O(n^2) 没问题,我没有看到超过 1k 的列表
  • 你为什么“希望”列表理解?

标签: python list class list-comprehension


【解决方案1】:

O(n^2),但代码更简单。

class ex(object):
    def __init__(self, tag, quantity):
        self.tag = tag
        self.quantity = quantity

    def __repr__(self):
        return '%s(%r, %r)' % (self.__class__.__name__, self.tag, self.quantity)

exes = [ex('a', 10.5), ex('b', 5.0), ex('c', 2.0), ex('a', 5.0), ex('c', -10.0)]
summed_exes = [ex(tag, sum(e.quantity for e in exes if e.tag == tag))
               for tag in sorted({e.tag for e in exes})]
print(summed_exes)

sorted 是可选的。

输出:

[ex('a', 15.5), ex('b', 5.0), ex('c', -8.0)]

【讨论】:

    【解决方案2】:

    我认为一个简单的循环实际上比这里的列表理解更好。通过跟踪已经看到的标签,可以实现 O(n) 复杂度:

    seen = {}
    
    for instance in in_list:
        try:
            existing = seen[instance.tag]
        except KeyError:
            seen[instance.tag] = instance
        else:
            existing.quantity += instance.quantity
    
    out_list = list(seen.values())  # can drop the "list" call on Python 2.x
    

    将使用每个组中的第一个实例,如果再次看到该标签,则会在之后更新。

    如果您希望保留标签的原始顺序,请为seen 变量添加collections.OrderedDict,而不是普通的dict。会有轻微的性能损失,但解决方案仍然是 O(n) 复杂度。

    【讨论】:

      【解决方案3】:

      这是一个创建新对象的 O(n) 解决方案:

      In [9]: class Ex(object):
         ...:     def __init__(self, tag, quantity):
         ...:         self.tag = tag
         ...:         self.quantity = quantity
         ...:
         ...:     def __repr__(self):
         ...:         return '%s(%r, %r)' % (self.__class__.__name__, self.tag, self.quantity)
         ...:
      
      In [10]: objs = [Ex('a', 10.5), Ex('b', 5.0),  Ex('c', 2.0), Ex('a', 5.0), Ex('c', -10.0)]
      
      In [11]: objs
      Out[11]: [Ex('a', 10.5), Ex('b', 5.0), Ex('c', 2.0), Ex('a', 5.0), Ex('c', -10.0)]
      
      In [12]: grouped = {}
      
      In [13]: for obj in objs:
          ...:     grouped[obj.tag] = grouped.get(obj.tag, 0) + obj.quantity
          ...:
      
      In [14]: new_objs = [Ex(k, v) for k,v in grouped.items()]
      
      In [15]: new_objs
      Out[15]: [Ex('b', 5.0), Ex('a', 15.5), Ex('c', -8.0)]
      

      如果订单很重要,您可以使用defaultdictCounterOrderedDict 来获得更好的体验。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-05
        • 2013-10-30
        • 1970-01-01
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多