Python: setについての備忘録

Python

setの機能:重複削除

以前setの利点として

setを使う理由の1つは要素の重複を無くす事

と書いた。

確かにiterableなデータを扱うにあたってのsetの良さの一つ。

公式チュートリアルの 5. Data Structuresの5.4. Setsにも下記の通り記載されている様に、メンバーシップに漏れやダブりがないかのテストや、ダブりの発見、削除に使える。

Python also includes a data type for sets. A setis an unordered collection with no duplicate elements. Basic uses include membership testing and eliminating duplicate entries.

setの機能:集合論(Set theory)

しかしsetの機能はそれだけではなく、listやdictやtupleには無い、便利に使える機能がある、と説明は続く。
それは数学の集合論(Set theory)に関する機能。

Set objects also support mathematical operations like union, intersection, difference, and symmetric difference.

そんな機能の備忘録。

これは公式チュートリアル、Built-in Typesのclass set/class frozenesetPEP 218 – Adding a Built-In Set Object Typeを参考にしています。

以下のa, b2つのset型データを用意。

a、bどちらもsetを作るコード。

>>> a = set(["red", "blue", "yellow", "red", "yellow", "blue", "blue"])
>>> b = {"green", "red", "orange", "white", "green", "orange"}
>>> a
{'red', 'yellow', 'blue'}
>>> b
{'green', 'red', 'white', 'orange'}

和集合(Union):論理和(OR)

和集合(Union)とは、二つのsetの要素を合わせた全てのset(重複の無い要素)。

論理演算の用語では論理和(OR)。

これを得るには、
(片方のset).union(もう一方のset)

演算子(operator)を使う場合は、
“片方のset | もう一方のset” で。

>>> a.union(b)
{'red', 'white', 'orange', 'blue', 'green', 'yellow'}
>>> a | b
{'red', 'white', 'orange', 'blue', 'green', 'yellow'}

a、b両方に含まれる全ての要素を返している。

積集合、共通部分、交差(intersection):論理積(AND)

積集合、共通部分、交差(intersection)とは、二つのsetに共通してある要素。

論理演算の用語では論理積(AND)。

これを得るには、
(片方のset).intersection(もう一方のset)

演算子(operator)を使う場合は
“片方のset & もう一方のset” で。

>>> a.intersection(b)
{'red'}
>>> a & b
{'red'}

今回はaとbのintersectionは”red”のみ。

差集合(difference):一方から見た否定(NOT)

差集合(difference)は、片方のsetから見て相手が持っていない要素を返す。

論理演算の用語ではその片方のsetから見た否定(NOT)。

これを得るには、
(片方のset).difference(もう一方のset)

演算子(operator)を使う場合は、
“片方のset – もう一方のset” で。

「片方のsetから見て相手が持っていないもの」なので、自分がどちらかによって返ってくるものが変わってくる。

>>> a.difference(b)
{'blue', 'yellow'}
>>> a - b
{'blue', 'yellow'}
>>> b.difference(a)
{'green', 'white', 'orange'}
>>> b - a
{'green', 'white', 'orange'}

aは{‘red’, ‘yellow’, ‘blue’}、
bは{‘green’, ‘red’, ‘white’, ‘orange’}なので、
aから見た相手(b)が持たないものは’red’以外の’blue’, ‘yellow’であり、
bから見た相手(a)が持たないものは’red’以外の’green’, ‘white’, ‘orange’である。

対称差集合(Symmetric Difference Set):排他的論理和(EOR, XOR)

対称差集合(Symmetric Difference Set)とは、双方のsetの要素の内、双方に含れれない片側だけに含まれた要素で作られた新しいsetを返す。

論理演算の用語では排他的論理和(EOR, XOR)

これを得るには、
(片方のset).symmetric_difference(もう一方のset)

演算子(operator)を使う場合は、
“片方のset ^ もう一方のset” で。

>>> a.symmetric_difference(b)
{'green', 'white', 'orange', 'blue', 'yellow'}
>>> a ^ b
{'green', 'white', 'orange', 'blue', 'yellow'}

双方のsetに含まれる”red”以外の全ての要素を含むsetが返されている。

共通の要素が有るか無いか

双方のsetに共通要素があるかチェックするには”isdisjoint()”を使用する。

共通要素が有ればFalse、共通要素が無ければTrueを返す。

>>> c = {'black', 'gray'} 
>>> a.isdisjoint(c)
True
>>> a.isdisjoint(b)
False

cの’black’、’gray’について、aにはどちらも含まれていないので、Trueが返ってくる。bには’black’が含まれているのでFalseが返ってくる。

そのsetはもう一つの集合の部分集合か?:subset

一般論

そのsetに含まれる要素が、他方のsetに全て含まれていればTrue、含まれていないものがあればFauseを返す。

これを得るには、
(片方のset).issubset(もう一方のset)
(片方のset).issuperset(もう一方のset)

演算子(operator)を使う場合は、
“片方のset < もう一方のset” または、
“片方のset <= もう一方のset”で。

bの要素’white’、’red’を含むset dと、bと要素が全く同じeを用意。

>>> d = {'white', 'red'}
>>> e = {'red', 'white', 'orange', 'green'}

# 異なる要素を含む場合
>>> d.issubset(a)
False  # dはaに含まれていない要素を含む
>>> d < a
False  # 同上

# 部分集合の場合(operator不使用)
>>> d.issubset(b)
True # dの要素はbに含まれているのでTrue
>>> d.issuperset(b)
False # dの要素がbに全て含まれていないのでFalse
>>> e.issubset(b)
True # eの要素はbに含まれているのでTrue
>>> e.issuperset(b)
True # eの要素がbに全て含まれているのでTrue

# 部分集合の場合(operator使用)
>>> d < b
True  # dの要素はbに含まれているのでTrue
>>> d <= b
True # dとbは同じでは無いものの、dの要素はbに含まれているのでTrue
>>> e < b
False  # eの要素はbに含まれていて、かつ全ての要素が同じ(イコール)で "<" では無いからFalse
>>> e <= b
True  # eの要素はbに含まれていて、かつ全ての要素が同じなのでTrue

注意:微妙にずれている範囲

注意しておきたいのは、issubset()、issuperset()と”<(>)” , “<=(>=)” の場合微妙に判定がずれる事。

issubset()は(片方のset) <= (他方のset)だけで双方が同一かは問わずTrueを返し、

issuperset()は (片方のset) <= (他方のset)でかつ、双方が同一ならTrueとする。

<(と>)は(片方のset) < (他方のset)を問い、同一の場合はFalseとし、

<= (と>=)はただ(片方のset) <= (他方のset)を問い双方が同一でなくてもTrueを返す。

issuperset()は一番厳しい判断をし、<=(と>=)は一番緩い判断、と言う理解。

注意:演算子(operator)を使う場合は注意

Built-in Typesのclass set/class frozenesetには下記説明がある。

Note, the non-operator versions of union()intersection()difference()symmetric_difference()issubset(), and issuperset() methods will accept any iterable as an argument. In contrast, their operator based counterparts require their arguments to be sets. This precludes error-prone constructions like set('abc') & 'cbs' in favor of the more readable set('abc').intersection('cbs').

(意訳)演算子(operator)を使わずに、union(), intersection(), difference(), symmetric_difference(), issubset(), issuperset() メソッドを使う分には細かい事を気にせず様々なiterableを使用できるが、operatorでメソッドを使う分には、引数は集合であることが必要にる。よって、例えばset(‘abc’) & ‘cbs’のようなエラーを起こしやすいコードは避けて、より読みやすい set(‘abc’).intersection(‘cbs’)と書くなど、operatorでは無いメソッドを使用する方が好ましい。

部分集合の判断の所で”<“と”>”についてはoperatorしか無いように思われるが、それ以外でoperatorを使う必要がある場合については、エラーの可能性がないか注意しながら使いたい。


コメント

タイトルとURLをコピーしました