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

时间:2012-04-05 07:51:41

标签: python list set

背景

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

objects = [Aobject, Bobject, Cobject]

其中

>>> Aobject != Bobject
True
>>> Aobject.id ==  Bobject.id
True

问题

我想要基于list的{​​{1}}个唯一对象。

这样的事情:

object.id

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

7 个答案:

答案 0 :(得分:20)

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]

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

(如果None,则表达式只能评估为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())

答案 1 :(得分:5)

如何使用dict(因为它的键是唯一的)?

假设我们有

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


Aobject = Object(1)
Bobject = Object(1)
Cobject = Object(2)
objects = [Aobject, Bobject, Cobject]

然后可以使用 Python 3

中的list理解生成Object id唯一的dict字段unique_objects = list({object_.id: object_ for object_ in objects}.values())
unique_objects = {object_.id: object_ for object_ in objects}.values()
Python 2.7

中的

unique_objects = dict([(object_.id, object_) for object_ in objects]).values()

并在 Python< 2.7

def unique(elements, key):
    return list({key(element): element for element in elements}.values())

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

elements

其中iterable可以是keycallablehashable,其中elements来自key seen set.add在我们的特定情况下,我会向operator.attrgetter('id')求价。

Marcin's answer工作正常,但不要看Pythonic给我,因为列表理解会从外部范围变异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))) )与list comprehension + set: 0.20700953400228173 dict comprehension: 0.1477799109998159

最后但并非不那么重要的部分:

基准

                   <label>Select Category <span>*</span></label>
                    <select id="cateabc" class="">
                        <option>Select Category</option>
                        <option value="Mobile">Mobiles</option>
                        </select>
                    <div class="clearfix"></div>

                    <label >Select Sub Category <span>*</span></label>
                    <select id="text-two" style="display :none">
                        <option>Please choose from above</option>
                    </select>

                    <div class="clearfix"></div>
                    <label >Mobile Brand <span>*</span></label>
                    <select id="text-three" style="display :none">
                        <option>Please choose from above</option>
                    </select>
                    <div class="clearfix"></div>
我的机器上的

给出了

$(function () {
                $("#cateabc").change(function () {
                    $("#text-two").show();
                    $("#text-two").load("textdata/" + $(this).val() + ".txt");
                });
            });
            $(function () {
                $("#text-two").change(function () {
                    $("#text-three").show();
                    $("#text-three").load("textdata/" + $(this).val() + ".txt");
                });
            });

答案 2 :(得分:2)

鉴于您的对象列表somelist类似于

[(Object [A] [1]), (Object [B] [1]), (Object [C] [2]), (Object [D] [2]), (Object [E] [3])]

你可以做这样的事情

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

答案 3 :(得分:0)

如果您可以更改对象的类,则可以添加在集合比较中使用的相应方法:

# Assumption: this is the 'original' object
class OriginalExampleObject(object):
    def __init__(self, name, nid):
        self.name = name
        self.id = nid
    def __repr__(self):
        return "(OriginalExampleObject [%s] [%s])" % (self.name, self.id)

class SetExampleObj(OriginalExampleObject):
    def __init__(self, name, nid):
        super(SetExampleObj, self).__init__(name, nid)
    def __eq__(self, other):
        return self.id == other.id
    def __hash__(self):
        return self.id.__hash__()


AObject = SetExampleObj("A", 1)
BObject = SetExampleObj("B", 1)
CObject = SetExampleObj("C", 2)

s = set()
s.add(AObject)
s.add(CObject)
print(s)

s.add(BObject)
print(s)

输出:

set([(OriginalExampleObject [A] [1]), (OriginalExampleObject [C] [2])])
set([(OriginalExampleObject [A] [1]), (OriginalExampleObject [C] [2])])

答案 4 :(得分:0)

您可以使用unique_everseen docs中可用的itertools配方。这在第三方库中也可用,例如toolz.unique。请注意,此方法将为给定属性保留对象的 first 实例。

from toolz import unique
from operator import attrgetter

res = list(unique(objects, key=attrgetter('id')))

如果懒惰的迭代器就足够了,则可以省略list转换。

答案 5 :(得分:-1)

一种相当简单的方法是

for obj in mylist:
    if obj.id not in s:
        s.add(obj.id)

这应该添加任何未见的ID。所花费的时间与源列表的大小呈线性关系。

答案 6 :(得分:-2)

objects = [Aobject, Bobject, Cobject]
unique_objects = {o['id']:o for o in objects}.values()