2017-05-25 202 views
1

我有一个函数,我希望一次一个地浏览一个自定义对象(给定中点)列表,并将对象与独特的中点对齐并放入一个新的列表。下面的代码给了我一个错误,即列表没有名为'midPoint'的属性,但是我不确定如何让代码在列表中搜索匹配中点的对象。有没有人有建议?在python中通过属性删除对象列表中的重复项

class Obj(): 
    def __init__(self, midPoint=[0,0]): 
     self.midPoint = midPoint 

obj1 = Obj(midPoint = [1,1]) 
obj2 = Obj(midPoint = [2,2]) 
obj3 = Obj(midPoint = [3,3]) 
obj4 = Obj(midPoint = [1,1]) 
obj5 = Obj(midPoint = [2,2]) 

l = [obj1, obj2, obj3, obj4, obj5] 

list_no_duplicates = [] 

def Delete_duplicates(list1):   
    for i in list1: 
     if i.midPoint not in list_no_duplicates.midPoint: 
     list_no_duplicates.append(x) 

Delete_duplicates(l) 
print list_no_duplicates 
+0

https://stackoverflow.com/questions/4169252/remove-duplicates-in-list-of-object-with-python –

+0

的可能的复制'list_no_duplicates'是一个列表,并没有一个' midPoint'属性。如果你想看看这个属性,你需要手头有一个Object对象。另外,'list_no_duplicates.append(x)'行中的'x'是什么? –

+0

是否要维护新列表中对象的顺序? –

回答

1

您可以使用与sorted函数一起itertools.groupby从列表中删除重复的条目。例如:

>>> from itertools import groupby 

>>> [next(obj) for i, obj in groupby(sorted(l, key=lambda x: x.midPoint), lambda x: x.midPoint)] 
[Obj: midPoint [1, 1], Obj: midPoint [2, 2], Obj: midPoint [3, 3]] 

在这里,我已经加入了__repr__()功能,以您的Obj类显示的midPoint与你的类值对象:

def __repr__(self): 
    return 'Obj: midPoint {}'.format(str(self.midPoint)) 

注:该解决方案不会维护原始列表中元素的顺序。新列表将根据midPoint的值进行排序。


下面是供您参考的完整代码:

from itertools import groupby 

class Obj(): 
    def __init__(self, midPoint=[0,0]): 
     self.midPoint = midPoint 
    def __repr__(self): 
     return 'Obj: midPoint {}'.format(str(self.midPoint)) 

obj1 = Obj(midPoint = [1,1]) 
obj2 = Obj(midPoint = [2,2]) 
obj3 = Obj(midPoint = [3,3]) 
obj4 = Obj(midPoint = [1,1]) 
obj5 = Obj(midPoint = [2,2]) 

l = [obj1, obj2, obj3, obj4, obj5] 
# `print(l)` will display: 
# [Obj: midPoint [1, 1], Obj: midPoint [2, 2], Obj: midPoint [3, 3], Obj: midPoint [1, 1], Obj: midPoint [2, 2]] 

# New list with unique `midPoint`s 
new_list = [next(obj) for i, obj in groupby(sorted(l, key=lambda x: x.midPoint), lambda x: x.midPoint)] 
# `print(new_list)` will display: 
# [Obj: midPoint [1, 1], Obj: midPoint [2, 2], Obj: midPoint [3, 3]] 
0

使用itertools.groupby

from itertools import groupby 
from operator import attrgetter as ga 
... 
l2 = [next(g) for k, g in groupby(sorted(l, key=ga('midPoint')), key=ga('midPoint'))] 

<script src="//repl.it/embed/ISOl/1.js"></script>

0

我们可以使用一个带有setdefault的字典,将该键用作midPoint的元组,并将该值作为列表添加到列表中,然后添加到该列表中。

那么我们有与中点的每个值列表的字典,我们可以迭代出[0]个元素:

def Delete_duplicates(list1): 
    deduped = {} 
    for i in list1: 
     deduped.setdefault(tuple(i.midPoint),[]).append(i) 
    return [j[0] for i,j in deduped.items()] 

如果你想所有这些去掉重复的,我们能做到的同样的,但只返回,如果我们的名单长度为1:

def Delete_duplicates(list1): 
    deduped = {} 
    for i in list1: 
     deduped.setdefault(tuple(i.midPoint),[]).append(1) 
    return [i for i in list1 if len(deduped[tuple(i.midPoint)]) == 1] 
0

如果你不关心在新的列表中的对象的顺序,你可以使用dict来实现这一目标:

new_list = {tuple(obj.midPoint): obj for obj in l}.values() 

# content of `new_list` will be: 
# [Obj: midPoint [3, 3], Obj: midPoint [1, 1], Obj: midPoint [2, 2]] 

使用键作为midPoint值的元组创建一个字典,并将值作为Obj类的对象。然后调用dict.values()方法获取值列表,即您的案例中的Obj对象列表。

但是,在Python 3.x中dict.values()返回一个dict_values类型的对象。为了将其转换为列表,明确其类型强制转换为list为:

new_list = list(new_list) 
0

如果我理解正确的话,这可能会按照您要求。

class Obj(): 
    def __init__(self, midPoint=[0,0]): 
     self.midPoint = midPoint 

obj1 = Obj(midPoint = [1,1]) 
obj2 = Obj(midPoint = [2,2]) 
obj3 = Obj(midPoint = [3,3]) 
obj4 = Obj(midPoint = [1,1]) 
obj5 = Obj(midPoint = [2,2]) 

l = [obj1, obj2, obj3, obj4, obj5] 
list_no_duplicates = [] 

# determines if midpoint already exists in any object inside list_no_duplicates 
def midpoint_exists(midpoint): 
    for obj in list_no_duplicates: 
     if obj.midPoint == midpoint: 
      return True 
    return False 

def Delete_duplicates(list1): 
    for obj in list1: 
     # if there are no object with this midPoint, appends 
     if not midpoint_exists(obj.midPoint): 
      list_no_duplicates.append(obj) 

Delete_duplicates(l) 
print list_no_duplicates 
相关问题