如何获取具有唯一属性的对象列表

Aka*_*007 18 python list set

背景

我有一个list.这list有很多对象.每个对象都有一个id.现在这些对象有不同的类型.

objects = [Aobject, Bobject, Cobject]
Run Code Online (Sandbox Code Playgroud)

哪里

>>> Aobject != Bobject
True
>>> Aobject.id ==  Bobject.id
True
Run Code Online (Sandbox Code Playgroud)

问题

我想要一个list基于的独特对象object.id.

像这样的东西:

set(objects, key=operator.attrgetter('id'))
Run Code Online (Sandbox Code Playgroud)

(这不起作用.但我想要这样的东西)

Mar*_*cin 21

seen = set() 

# never use list as a variable name
[seen.add(obj.id) or obj for obj in mylist if obj.id not in seen]
Run Code Online (Sandbox Code Playgroud)

这是因为set.add返回None,因此列表推导中的表达式总是会产生obj,但obj.id前提是尚未添加seen.

(表达式只能评估Noneif obj is None;在这种情况下,obj.id会引发异常.如果mylist包含None值,请将测试更改为if obj and (obj.id not in seen))

请注意,这将为您提供列表中具有给定ID的第一个对象.@ Abhijit的回答会给你最后一个这样的对象.

更新:

或者,有序的指令可能是一个不错的选择:

import collections
seen = collections.OrderedDict()

for obj in mylist:
    # eliminate this check if you want the last item
    if obj.id not in seen:
       seen[obj.id] = obj

list(seen.values())
Run Code Online (Sandbox Code Playgroud)


Abh*_*jit 5

给定你的对象列表somelist是这样的

[(Object [A] [1]), (Object [B] [1]), (Object [C] [2]), (Object [D] [2]), (Object [E] [3])]
Run Code Online (Sandbox Code Playgroud)

你可以做这样的事情

>>> {e.id:e for e in somelist}.values()
[(Object [B] [1]), (Object [D] [2]), (Object [E] [3])]
Run Code Online (Sandbox Code Playgroud)

  • 这很酷。请注意,它将给出具有给定 ID 的最后一个对象。 (2认同)

Aza*_*kov 5

如何使用dict(由于其键是唯一的)?

假设我们有

class Object:
    def __init__(self, id):
        self.id = id


Aobject = Object(1)
Bobject = Object(1)
Cobject = Object(2)
objects = [Aobject, Bobject, Cobject]
Run Code Online (Sandbox Code Playgroud)

然后可以使用Python 3中的理解来生成list具有Objects的唯一by id字段dict

unique_objects = list({object_.id: object_ for object_ in objects}.values())
Run Code Online (Sandbox Code Playgroud)

Python 2.7中

unique_objects = {object_.id: object_ for object_ in objects}.values()
Run Code Online (Sandbox Code Playgroud)

并且在Python <2.7中

unique_objects = dict([(object_.id, object_) for object_ in objects]).values()
Run Code Online (Sandbox Code Playgroud)

最后,我们可以编写函数(Python 3版本)

def unique(elements, key):
    return list({key(element): element for element in elements}.values())
Run Code Online (Sandbox Code Playgroud)

where elements可能是any iterablekey并且some是callable从中返回hashable对象的对象elements(在我们的特定情况下key等于operator.attrgetter('id'))。

马辛的答案工作正常,但看起来并不符合Python到我,因为列表解析变异seen来自外部范围对象,也有背后使用某种神奇的set.add方法,并比较其结果(这是None用)obj

最后但同样重要的部分:

基准测试

setup = '''
import random


class Object:
    def __init__(self, id):
        self.id = id


objects = [Object(random.randint(-100, 100))
           for i in range(1000)]
'''
solution = '''
seen = set()
result = [seen.add(object_.id) or object_
          for object_ in objects
          if object_.id not in seen]
'''
print('list comprehension + set: ',
      min(timeit.Timer(solution, setup).repeat(7, 1000)))
solution = '''
result = list({object_.id: object_
               for object_ in objects}.values())
'''
print('dict comprehension: ',
      min(timeit.Timer(solution, setup).repeat(7, 1000)))
Run Code Online (Sandbox Code Playgroud)

在我的机器上给

list comprehension + set:  0.20700953400228173
dict comprehension:  0.1477799109998159
Run Code Online (Sandbox Code Playgroud)