2017-06-10 1 views
-1

複雑なオブジェクトを持つ複数のリストがあります。私はブール演算をしたいまたは彼らと複雑なデータオブジェクトを持つ複数のリストでAND、ORを実行しないでください

および:結果のリストには、すべてのソースリストが使用されているすべてのオブジェクトが含まれます。重複はありません。

または:結果リストには、使用されているすべてのソースリストのすべてのオブジェクトが含まれている必要があります。重複はありません。

:募集リストには、非一覧に存在しないソースリストの既存のオブジェクトのみが含まれている必要があります。

#!/usr/bin/env python3 
# -*- coding: utf-8 -*- 

# the "complex data" 
class Person: 
    def __init__(self, name): 
     # assume the 'name' as unique 
     self.name = name 

# create example data 
mylistA = [Person('Anna'), 
      Person('Bob'), 
      Person('Jane'), 
      Person('Alfred')] 

mylistB = [Person('Simon'), 
      Person('Anna'), 
      Person('Doris'), 
      Person('Bob')] 

mylistC = [Person('Bob'), 
      Person('Rosi'), 
      Person('Becky'), 
      Person('Anna')] 

mylistD = [Person('Alfred'), 
      Person('Bob'), 
      Person('Chris'), 
      Person('Susi')] 

def doAND(some_lists): 
    pass 

def doOR(some_lists): 
    pass 

def doNOT(one_list, not_list): 
    pass 

# should result in 'Anna', 'Bob' 
resultAND = doAND([mylistA, mylistB, mylistC]) 
print(resultAND) 

# should result in 'Anna', 'Bob', 'Jane', 'Alfred', 'Simon', 'Doris', 'Rosi', 
# 'Becky' 
resultOR = doOR([mylistA, mylistB, mylistC]) 
print(resultOR) 

# 'Anna' 
resultNOT = doNOT(resultAND, mylistD) 
print(resultNOT) 

背景情報実際のシナリオの「複雑なオブジェクト」は、sqlalchemyオブジェクトです。私のここでの例の文脈におけるそれらの "身元"は主キーではありません。彼らの「アイデンティティ」は、メンバーの共同体(単純な例:「ファーストネーム」、「ラストネーム」、「生年月日」)に基づいて形成されます。

+1

です。 –

+2

"複雑なデータ"のために '__eq__'を実装する必要があります –

答えて

1

正しいヒントをくれた@ criket_007に感謝します。 Pythonはとても簡単です! 複合データオブジェクトの演算子を作成するだけです。次に、それらをsetとして扱うことができます。

あなたのデータは `str`基づいていた場合、これは` set`sとOH-SO-簡単だろう更新例

#!/usr/bin/env python3 
# -*- coding: utf-8 -*- 

# the "complex data" 
class Person: 
    def __init__(self, name): 
     # assume the 'name' as unique 
     self.name = name 
    def __str__(self): 
     return self.name 
    def __repr__(self): 
     return '{}:{}'.format(id(self), self.__str__()) 
    def __hash__(self): 
     return hash(self.name) 

# create example data 
mylistA = [Person('Anna'), 
      Person('Bob'), 
      Person('Jane'), 
      Person('Alfred')] 
sa = set(mylistA) 

mylistB = [Person('Simon'), 
      Person('Anna'), 
      Person('Doris'), 
      Person('Bob')] 
sb = set(mylistB) 

mylistC = [Person('Bob'), 
      Person('Rosi'), 
      Person('Becky'), 
      Person('Anna')] 
sc = set(mylistC) 

mylistD = [Person('Alfred'), 
      Person('Bob'), 
      Person('Chris'), 
      Person('Susi')] 
sd = set(mylistD) 

# should result in 'Anna', 'Bob' 
resultAND = sa.intersection(sb, sc) 
print('AND: {}\n'.format(resultAND)) 

# should result in 'Anna', 'Bob', 'Jane', 'Alfred', 'Simon', 'Doris', 'Rosi', 
# 'Becky' 
resultOR = sa.union(sb, sc) 
print('OR: {}\n'.format(resultOR)) 

# 'Anna' 
resultNOT = resultAND.difference(sd) 
print('NOT: {}\n'.format(resultNOT)) 
+0

@lhk彼はあなたの意見を落としたからといって彼の答えを下げてはいけません。 –

+0

@lhkヒストロイやタイムスタンプを見てください。あなたの答えの__first version__は私の質問に合っていませんでした。あなたの更新をありがとう。あなたのヒントをありがとう、私は私の答えを更新しました。 – buhtz

1

あなたが考えることができる提案があります。 listdictとしてください。これにより、これらのセットベースの操作を(ある程度まで)実行することが容易になります。

mydictA = {x.name : x for x in mylistA } 

とにかく、元の問題に戻ってください。 doANDは本質的には交差操作です。 doORは組合であり、doNOTは差分操作です。

次に、doANDの例を示します。あなたは残りの部分を把握できるはずです。

def doAND(list1, list2): 
    dict1 = {x.name : x for x in list1} 
    dict2 = {x.name : x for x in list2} 
    common_names = set(dict1.keys()).intersection(set(dict2.keys())) 
    return [dict1[x] for x in common_names if x in dict1] + [dict2[x] for x in common_names if x in dict2] 

doORのために、あなたは set1.union(set2)が必要になり、そして doNOTのために、あなたは set1 - set2を行う必要があります。

これが役に立ちます。

1

リストの代わりにsetを使用する必要があります。 これは、重複を回避し、便利な方法であなたの操作のすべてを提供しています:

a=[1,2,3,4,5] 
b=[1,2,3] 

a=set(a) 
b=set(b) 

# OR 
a | b # [1,2,3,4,5] 

# AND 
a & b # [1,2,3] 

# NOT 
a - b # [4,5] 

あなたも、複雑なデータ型のためにこれを使用することができます。彼らは2つの基準を満たす必要があります。

  • __eq__がセットは、重複を探すために__eq__を必要

実装する

  • __hash__ニーズを実装する必要があります。しかし、__eq__だけを実装すると、デフォルトの__hash__実装が削除されます。

    __eq____hash__が一貫している必要があるからです。 だから、__hash__

    組み込みhash()機能のご利用には、実際にhashlibと私のバージョンよりもはるかに進歩して再実装する必要があります。だから私はそれを更新しました。 驚くべきことに、__hash__の実装では、同じハッシュを持つオブジェクトが等しくなければならない不変式であっても、__eq__の暗黙的な実装は提供されません。したがって、__eq____hash__の両方を実装する必要があります。この答えの以前のバージョンでは間違っていました。

    パフォーマンス上の理由から、__eq__オペレータを再度実装する必要があるかもしれません。 hash()の機能はどれくらい速いのか分かりませんが、セットが大きくなると、名前を最初にハッシュするのではなく、直接比較するのに便利な最適化になるかもしれません。

    class Person: 
        def __init__(self, name): 
         # assume the 'name' as unique 
         self.name = name 
    
        def __hash__(self): 
         return hash(self.name) 
    
        def __eq__(self, other): 
         return self.name == other.name 
         # return hash(self) == hash(other) 
    
        def __repr__(self): 
         return self.name 
    
    
    persons = [Person("a"), Person("b"), Person("a")] 
    
    print(persons) # [a, b, a] 
    
    persons_set= set(persons) 
    
    print(persons_set) # [a, b] 
    
  • +0

    私が"複雑なデータオブジェクト "を要求したところで私の質問に適合しません。 – buhtz

    +1

    これはかなりうまくいくと思います。重複を避ける必要がある場合は、重複が何であるかを定義する必要があります。 Pythonでは、これはハッシュ関数で行われます。 – lhk

    +1

    ここでは '__eq __()'を実装しました。どうして?私は必要かどうか?私はそれをテストすることができません。そしてなぜあなたは '__hash()__'で 'hash()'を使わなかったのですか?あなたのソリューションの利点は何ですか? – buhtz

    関連する問題