如何检查对象列表中的重复属性并合并它们

时间:2018-02-06 14:50:58

标签: python python-3.x list object data-structures

我有一个包含属性qtconsconsper的对象列表,并且必须合并具有相同consper值的所有对象。最好的方法是什么?该列表已按consper排序。

实施例: 使用类house的对象列表:

class house():
    def __init__(self, qt, cons, consper):
        self.qt = qt
        self.cons = cons
        self.consper = consper

转动此列表:

l = [
house(2, 20, 10),
house(3, 31, 10),
house(6, 70, 11),
house(2, 40, 20),
house(1, 25, 25)]

进入此列表:

l_new = [
house(5, 51, 10),
house(6, 70, 11),
house(2, 40, 20),
house(1, 25, 25)]

通过添加前两个对象(因为它们的属性包含等效)

4 个答案:

答案 0 :(得分:2)

如果项目已按该属性排序,您可以使用itertools.groupby获取组,sum获取其他属性的总和。您还必须首先将组转换为list,因为它们是迭代器。

>>> from itertools import groupby
>>> house.__repr__ = lambda h: "house(%r, %r, %r)" % (h.qt, h.cons, h.consper)
>>> [house(sum(h.qt for h in g), sum(h.cons for h in g), k) 
...  for k, g in ((k, list(g)) for k, g in groupby(l, key=lambda h: h.consper))]
[house(5, 51, 10), house(6, 70, 11), house(2, 40, 20), house(1, 25, 25)]

或使用字典:

>>> d = {}
>>> for h in l:
...     qt, cons = d.get(h.consper, (0, 0))
...     d[h.consper] = qt + h.qt, cons + h.cons
...
>>> [house(a, b, c) for a, (b, c) in d.items()]
[house(25, 1, 25), house(10, 5, 51), house(11, 6, 70), house(20, 2, 40)]

答案 1 :(得分:1)

您可以使用Failed to invoke gs

itertools.groupby

输出:

import itertools
class house():
  def __init__(self, qt, cons, consper):
    self.qt = qt
    self.cons = cons
    self.consper = consper
  def __repr__(self):
    return self.__class__.__name__+"({qt}, {cons}, {consper})".format(**self.__dict__)

l = [house(2, 20, 10),
 house(3, 31, 10),
 house(6, 70, 11),
 house(2, 40, 20),
 house(1, 25, 25)]
new_l = [(a, [(i.qt, i.cons) for i in list(b)]) for a, b in itertools.groupby(sorted(l, key=lambda x:x.consper), key=lambda x:x.consper)]
final_data = [house(*[sum(i) for i in zip(*b)]+[a]) for a, b in new_l]

答案 2 :(得分:1)

不使用itertools,你可以这样做:

class House():
        def __init__(self, qt, cons, consper):
            self.qt = qt
            self.cons = cons
            self.consper = consper

        def __str__(self):
            return "House(" + str(self.qt) + "," + str(self.cons) + "," + str(self.consper) + ")"

        def __repr__(self):
            return self.__str__()

def merge_dups(house_list):
    res = []
    house_map = {}
    for h in house_list:
        if h.consper in house_map:
            other_house = house_map[h.consper]
            merged_house = House(h.qt + other_house.qt,
                                 h.cons + other_house.cons,
                                 h.consper)
            res.remove(other_house)
            res.append(merged_house)

        else:
            house_map[h.consper] = h
            res.append(h)
    return res

print(merge_dups([
House(2, 20, 10),
House(3, 31, 10),
House(6, 70, 11),
House(2, 40, 20),
House(1, 25, 25)]))

输出

[House(5,51,10), House(6,70,11), House(2,40,20), House(1,25,25)]

答案 3 :(得分:0)

一个简单的解决方案是按如下方式使用词典:

l = [
house(2, 20, 10),
house(3, 31, 10),
house(6, 70, 11),
house(2, 40, 20),
house(1, 25, 25)]
dic= {}
for x in l :
    temp = dic.get(x.consper,house(0,0,0))
    x.qt += temp.qt
    x.cons += temp.cons
    dic[x.consper]=x

print('####################')
for x in dic.keys():
    print(x)