2016-09-21 2 views
0

は、だから私は、このクラスを持っているとしましょう:Pythonの別々の重複オブジェクト別のリストに

class Spam(object): 
    def __init__(self, a): 
     self.a = a 

そして今、私は、これらのオブジェクトを持っている:

s1 = Spam((1, 1, 1, 4)) 

s2 = Spam((1, 2, 1, 4)) 

s3 = Spam((1, 2, 1, 4)) 

s4 = Spam((2, 2, 1, 4)) 

s5 = Spam((2, 1, 1, 8)) 

s6 = Spam((2, 1, 1, 8)) 

objects = [s1, s2, s3, s4, s5, s6] 

ので、この方法のいくつかの種類を実行した後、私が必要1つのリストに同じa属性値を持つオブジェクトと、固有のa属性を持つオブジェクトを持つ2つのリストを持つことができます。

dups = [s2, s3, s5, s6] 
normal = [s1, s4] 

だから、重複を取得のようなもので、それに加えて、それはまた同じa属性値を共有するオブジェクトのも、最初のオカレンスを追加する必要があります。このよう

私はこの方法を書いており、機能しているようですが、私の意見ではかなり醜いです。

def eggs(objects): 
    vals = [] 
    dups = [] 
    normal = [] 
    for obj in objects: 
     if obj.a in vals: 
      dups.append(obj) 
     else: 
      normal.append(obj) 
      vals.append(obj.a) 
    dups_vals = [o.a for o in dups] 
    # separate again 
    new_normal = [] 
    for n in normal: 
     if n.a in dups_vals: 
      dups.append(n) 
     else: 
      new_normal.append(n) 
    return dups, new_normal 

誰もがこのような問題に対してより適切なパイソン法を書くことができますか?

答えて

2

a属性をキーとして、オブジェクトを辞書にグループ化します。それから私はグループの大きさでそれらを分けます。

import collections 

def separate_dupes(seq, key_func): 
    d = collections.defaultdict(list) 
    for item in seq: 
     d[key_func(item)].append(item) 
    dupes = [item for v in d.values() for item in v if len(v) > 1] 
    uniques = [item for v in d.values() for item in v if len(v) == 1] 
    return dupes, uniques 

class Spam(object): 
    def __init__(self, a): 
     self.a = a 
    #this method is not necessary for the solution, just for displaying the results nicely 
    def __repr__(self): 
     return "Spam({})".format(self.a) 

s1 = Spam((1, 1, 1, 4)) 
s2 = Spam((1, 2, 1, 4)) 
s3 = Spam((1, 2, 1, 4)) 
s4 = Spam((2, 2, 1, 4)) 
s5 = Spam((2, 1, 1, 8)) 
s6 = Spam((2, 1, 1, 8)) 
objects = [s1, s2, s3, s4, s5, s6] 

dupes, uniques = separate_dupes(objects, lambda item: item.a) 
print(dupes) 
print(uniques) 

結果:

[Spam((2, 1, 1, 8)), Spam((2, 1, 1, 8)), Spam((1, 2, 1, 4)), Spam((1, 2, 1, 4))] 
[Spam((1, 1, 1, 4)), Spam((2, 2, 1, 4))] 
1

あなたは

def __eq__(self, other): 
    return self.a == other.a 

として定義され、Spam__eq__メソッドを追加するなら、あなたは

# you can inline this if you want, just wanted to give it a name 
def except_at(elems, ind): 
    return elems[:ind] + elems[ind+1:] 
dups = [obj for (i, obj) in enumerate(objects) if obj in except_at(objects, i)] 
normal = [obj for (i, obj) in enumerate(objects) if obj not in except_at(objects, i)] 
+0

これは私を投げているようだ 'TypeError例外:それは私の端にありますが「スパム」オブジェクトは、私は疑問に思う' を添字化されていない私は時間があるとき、それになりますあなたの 'except_at'関数 – MooingRawr

+0

私の謝罪!間違った変数を 'except_at'に渡しました。修正しました。 –

0
ようなもので、非常に簡単にこれを行うことができます

あなたの二つのリスト、オブジェクトのリストがない場合は、今、これを行うには

[o for o in objects if o.a in common], [o for o in objects if o.a not in common] 
0

一つの方法ですが:collections.Counterを使用して、これらは複数に共通するキーがあります大きすぎると、オブジェクトのリストをソートし、groupbyを適用して重複を取得します。リストをソートするために、オブジェクトの.a属性の値を抽出するキー関数を提供します。

from operator import attrgetter 
from itertools import groupby 

class Spam(object): 
    def __init__(self, a): 
     self.a = a 

    def __repr__(self): 
     return 'Spam({})'.format(self.a) 

s1 = Spam((1, 1, 1, 4)) 
s2 = Spam((1, 2, 1, 4)) 
s3 = Spam((1, 2, 1, 4)) 
s4 = Spam((2, 2, 1, 4)) 
s5 = Spam((2, 1, 1, 8)) 
s6 = Spam((2, 1, 1, 8)) 

objects = [s1, s2, s3, s4, s5, s6] 

keyfunc = attrgetter('a') 

dupe, unique = [], [] 
for k, g in groupby(sorted(objects, key=keyfunc), key=keyfunc): 
    g = list(g) 
    target = unique if len(g) == 1 else dupe 
    target.extend(g) 

print('dupe', dupe) 
print('unique', unique) 

出力は

dupe [Spam((1, 2, 1, 4)), Spam((1, 2, 1, 4)), Spam((2, 1, 1, 8)), Spam((2, 1, 1, 8))] 
unique [Spam((1, 1, 1, 4)), Spam((2, 2, 1, 4))] 
関連する問題