29

バックグラウンド

私は持っていlistます。これlistには多くのオブジェクトがあります。各オブジェクトには。がありidます。これで、オブジェクトはさまざまなタイプになります。

objects = [Aobject, Bobject, Cobject]

どこ

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

問題

listに基づいたユニークなオブジェクトが必要ですobject.id

このようなもの:

set(objects, key=operator.attrgetter('id'))

(これは機能しません。しかし、私はこのようなものが欲しいです)

4

7 に答える 7

35
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.idseen

(式は、 ;のNone場合にのみ評価できます。その場合、例外が発生します。値が含まれている場合は、テストをに変更してください)obj is Noneobj.idmylistNoneif obj and (obj.id not in seen)

これにより、指定されたIDを持つリストの最初のオブジェクトが得られることに注意してください。@Abhijitの答えはあなたに最後のそのようなオブジェクトを与えるでしょう。

アップデート:

あるいは、ordereddictが良い選択かもしれません:

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())
于 2012-04-05T07:59:09.303 に答える
7

dict(キーは一意なので)使用してみませんか?

私たちが持っていると仮定して

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


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

次にlistPython 3の理解を使用してObject、フィールドごとに一意のsidを生成できます。dict

unique_objects = list({object_.id: object_ for object_ in objects}.values())

Python2.7

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 3バージョン)

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

ここで、elementsはanyiterableであり、keyオブジェクトをcallable返すものです(特定の場合はに等しい)。hashableelementskeyoperator.attrgetter('id')

Marcinの答えseenはうまく機能しますが、リスト内包表記はオブジェクトを外部スコープから変更するため、Pythonicには見えません。また、メソッドを使用してその結果( )set.addをと比較することには魔法があります。Noneobj

そして最後の、しかしそれほど重要ではない部分:

基準

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
于 2018-03-08T08:49:43.853 に答える
3

オブジェクトのリストを考えると、次の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])]
于 2012-04-05T08:24:45.667 に答える
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])])
于 2012-04-05T08:14:22.850 に答える
0

ドキュメントunique_everseenで利用可能なレシピを使用できます。これは、サードパーティのライブラリでも利用できます。このメソッドは、特定の属性のオブジェクトの最初のインスタンスを保持することに注意してください。itertools toolz.unique

from toolz import unique
from operator import attrgetter

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

遅延イテレータで十分な場合は、list変換を省略できます。

于 2018-09-27T14:46:23.923 に答える
-1

これを行うためのかなり簡単な方法は次のようになります

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

そして、これは見られないIDを追加する必要があります。かかる時間は、ソースリストのサイズに比例します。

于 2012-04-05T08:11:04.380 に答える
-1
objects = [Aobject, Bobject, Cobject]
unique_objects = {o['id']:o for o in objects}.values()
于 2019-09-19T06:06:35.267 に答える