8.7. "sets" --- 重複のない要素の順序なしコレクション
****************************************************

バージョン 2.3 で追加.

バージョン 2.6 で非推奨: 組み込みの "set"/"frozenset" 型がこのモジュー
ルを置き換えます。

"sets" モジュールは、ユニークな要素の順序なしコレクションを構築し、操
作するためのクラスを提供します。帰属関係のテストやシーケンスから重複を
取り除いたり、積集合・和集合・差集合・対称差集合のような標準的な数学操
作などを含みます。

集合は、他のコレクションと同様、 "x in set", "len(set)", "for x in
set" をサポートします。コレクションには順序がないので、集合は挿入の順
序や要素の位置を記録しません。従って、集合はインデクシング、スライシン
グ、その他のシーケンス的な振舞いをサポートしません。

ほとんどの集合のアプリケーションは、 "__hash__()" を除いてすべての集合
のメソッドを提供する "Set" クラスを使用します。ハッシュを要求する高度
なアプリケーションについては、 "ImmutableSet" クラスが "__hash__()" メ
ソッドを加えているが、集合の内容を変更するメソッドは省略されます。
"Set" と "ImmutableSet" は、何が集合であるか決めるのに役立つ
("isinstance(obj, BaseSet)") 抽象クラス "BaseSet" から派生します。

集合クラスは辞書を使用して実装されます。このことから、集合の要素にする
には辞書のキーと同様の要件を満たさなければなりません。具体的には、要素
になるものには "__eq__()" と "__hash__()" が定義されているという条件で
す。その結果、集合はリストや辞書のような変更可能な要素を含むことができ
ません。しかしそれらは、タプルや "ImmutableSet" のインスタンスのような
不変コレクションを含むことができます。集合の集合の実装中の便宜について
は、内部集合が自動的に変更不可能な形式に変換されます。例えば、
"Set([Set(['dog'])])" は "Set([ImmutableSet(['dog'])])" へ変換されます
。

class sets.Set([iterable])

   新しい空の "Set" オブジェクトを構築します。もしオプション
   *iterable* が与えられたら、イタレータから得られた要素を備えた集合と
   して更新します。 *iterable* 中の全ての要素は、変更不可能であるか、
   または 不変に自動変換するためのプロトコル で記述されたプロトコルを
   使って変更不可能なものに変換可能であるべきです。

class sets.ImmutableSet([iterable])

   新しい空の "ImmutableSet" オブジェクトを構築します。もしオプション
   *iterable* が与えられたら、イタレータから得られた要素を備えた集合と
   して更新します。 *iterable* 中の全ての要素は、変更不可能であるか、
   または 不変に自動変換するためのプロトコル で記述されたプロトコルを
   使って変更不可能なものに変換可能であるべきです。

   "ImmutableSet" オブジェクトは "__hash__()" メソッドを備えているので
   、集合要素または辞書キーとして使用することができます。
   "ImmutableSet" オブジェクトは要素を加えたり取り除いたりするメソッド
   を持っていません。したがって、コンストラクタが呼ばれたとき要素はす
   べて知られていなければなりません。


8.7.1. Set オブジェクト
=======================

"Set" と "ImmutableSet" のインスタンスはともに、以下の操作を備えていま
す:

+---------------------------------+--------------+-----------------------------------+
| 演算                            | 等価な演算   | 結果                              |
+=================================+==============+===================================+
| "len(s)"                        |              | 集合 *s* の要素数 (濃度)          |
+---------------------------------+--------------+-----------------------------------+
| "x in s"                        |              | *x* が *s* に帰属していれば真を返 |
|                                 |              | す                                |
+---------------------------------+--------------+-----------------------------------+
| "x not in s"                    |              | *x* が *s* に帰属していなければ真 |
|                                 |              | を返す                            |
+---------------------------------+--------------+-----------------------------------+
| "s.issubset(t)"                 | "s <= t"     | *s* のすべての要素が *t* に帰属し |
|                                 |              | ていれば真を返す                  |
+---------------------------------+--------------+-----------------------------------+
| "s.issuperset(t)"               | "s >= t"     | *t* のすべての要素が *s* に帰属し |
|                                 |              | ていれば真を返す                  |
+---------------------------------+--------------+-----------------------------------+
| "s.union(t)"                    | "s | t"      | *s* と *t* の両方の要素からなる新 |
|                                 |              | しい集合                          |
+---------------------------------+--------------+-----------------------------------+
| "s.intersection(t)"             | "s & t"      | *s* と *t* で共通する要素からなる |
|                                 |              | 新しい集合                        |
+---------------------------------+--------------+-----------------------------------+
| "s.difference(t)"               | "s - t"      | *s* にあるが *t* にない要素からな |
|                                 |              | る新しい集合                      |
+---------------------------------+--------------+-----------------------------------+
| "s.symmetric_difference(t)"     | "s ^ t"      | *s* と *t* のどちらか一方だけに属 |
|                                 |              | する要素からなる集合              |
+---------------------------------+--------------+-----------------------------------+
| "s.copy()"                      |              | *s* の浅いコピーからなる集合      |
+---------------------------------+--------------+-----------------------------------+

演算子を使わない書き方である "union()", "intersection()",
"difference()", および "symmetric_difference()" は任意のイテレート可能
オブジェクトを引数として受け取るのに対し、演算子を使った書き方の方では
引数は集合型でなければならないので注意してください。これはエラーの元と
なる "Set('abc') & 'cbs'" のような書き方を排除し、より可読性のある
"Set('abc').intersection('cbs')" を選ばせるための仕様です。

バージョン 2.3.1 で変更: 以前は全ての引数が集合型でなければなりません
でした。

加えて、 "Set" と "ImmutableSet" は集合間の比較をサポートしています。
二つの集合は、各々の集合のすべての要素が他方に含まれて (各々が他方の部
分集合) いる場合、かつその場合に限り等価になります。ある集合は、他方の
集合の真の部分集合 (proper subset、部分集合であるが非等価) である場合
、かつその場合に限り、他方の集合より小さくなります。ある集合は、他方の
集合の真の上位集合 (proper superset、上位集合であるが非等価) である場
合、かつその場合に限り、他方の集合より大きくなります。

部分集合比較やと等値比較では、完全な順序決定関数を一般化できません。た
とえば、互いに素な 2 つの集合は等しくありませんし、互いの部分集合でも
ないので、 "a<b", "a==b", "a>b" は *すべて* "False" を返します。したが
って集合は "__cmp__()" メソッドを実装しません。

集合は半順序（部分集合関係）しか定義しないので、集合のリストにおける
"list.sort()" メソッドの出力は未定義です。

以下は "ImmutableSet" で利用可能であるが "Set" にはない操作です:

+---------------+--------------------------------+
| 演算          | 結果                           |
+===============+================================+
| "hash(s)"     | *s* のハッシュ値を返す         |
+---------------+--------------------------------+

以下は "Set" で利用可能であるが "ImmutableSet" にはない操作です:

+----------------------------------------+---------------+-----------------------------------+
| 演算                                   | 等価な演算    | 結果                              |
+========================================+===============+===================================+
| "s.update(t)"                          | *s* |= *t*    | *t* を加えた要素からなる集合 *s*  |
|                                        |               | を返します                        |
+----------------------------------------+---------------+-----------------------------------+
| "s.intersection_update(t)"             | *s* &= *t*    | *t* でも見つかった要素だけを持つ  |
|                                        |               | 集合 *s* を返します               |
+----------------------------------------+---------------+-----------------------------------+
| "s.difference_update(t)"               | *s* -= *t*    | *t* にあった要素を取り除いた後の  |
|                                        |               | 集合 *s* を返します               |
+----------------------------------------+---------------+-----------------------------------+
| "s.symmetric_difference_update(t)"     | *s* ^= *t*    | *s* と *t* のどちらか一方だけに属 |
|                                        |               | する要素からなる集合 *s* を返しま |
|                                        |               | す                                |
+----------------------------------------+---------------+-----------------------------------+
| "s.add(x)"                             |               | 要素 *x* を集合 *s* に加えます    |
+----------------------------------------+---------------+-----------------------------------+
| "s.remove(x)"                          |               | 要素 *x* を集合 *s* から取り除き  |
|                                        |               | ます; *x* がなければ "KeyError"   |
|                                        |               | を送出 します                     |
+----------------------------------------+---------------+-----------------------------------+
| "s.discard(x)"                         |               | 要素 *x* が存在すれば、集合 *s*   |
|                                        |               | から取り除きます                  |
+----------------------------------------+---------------+-----------------------------------+
| "s.pop()"                              |               | *s* から任意に要素を取り除き、そ  |
|                                        |               | れを返します; 集合が空なら        |
|                                        |               | "KeyError" を送出します           |
+----------------------------------------+---------------+-----------------------------------+
| "s.clear()"                            |               | 集合 *s* からすべての要素を取り除 |
|                                        |               | きます                            |
+----------------------------------------+---------------+-----------------------------------+

演算子を使わない書き方である "update()", "intersection_update()",
"difference_update()", および "symmetric_difference_update()" は任意の
イテレート可能オブジェクトを引数として受け取ることに注目してください。

バージョン 2.3.1 で変更: 以前は全ての引数が集合型でなければなりません
でした。

もう一つ注意を述べますが、このモジュールでは "union_update()" が
"update()" の別名として含まれています。このメソッドは後方互換性のため
に残されているものです。プログラマは組み込みの "set()" および
"frozenset()" でサポートされている "update()" を選ぶべきです。


8.7.2. 使用例
=============

>>> from sets import Set
>>> engineers = Set(['John', 'Jane', 'Jack', 'Janice'])
>>> programmers = Set(['Jack', 'Sam', 'Susan', 'Janice'])
>>> managers = Set(['Jane', 'Jack', 'Susan', 'Zack'])
>>> employees = engineers | programmers | managers           # union
>>> engineering_management = engineers & managers            # intersection
>>> fulltime_management = managers - engineers - programmers # difference
>>> engineers.add('Marvin')                                  # add element
>>> print engineers # doctest: +SKIP
Set(['Jane', 'Marvin', 'Janice', 'John', 'Jack'])
>>> employees.issuperset(engineers)     # superset test
False
>>> employees.update(engineers)         # update from another set
>>> employees.issuperset(engineers)
True
>>> for group in [engineers, programmers, managers, employees]: # doctest: +SKIP
...     group.discard('Susan')          # unconditionally remove element
...     print group
...
Set(['Jane', 'Marvin', 'Janice', 'John', 'Jack'])
Set(['Janice', 'Jack', 'Sam'])
Set(['Jane', 'Zack', 'Jack'])
Set(['Jack', 'Sam', 'Jane', 'Marvin', 'Janice', 'John', 'Zack'])


8.7.3. 不変に自動変換するためのプロトコル
=========================================

集合は変更不可能な要素だけを含むことできます。都合上、変更可能な "Set"
オブジェクトは、集合要素として加えられる前に、自動的に "ImmutableSet"
へコピーします。

そのメカニズムはハッシュ可能な (*hashable*) 要素を常に加えることですが
、もしハッシュ不可能な場合は、その要素は変更不可能な等価物を返す
"__as_immutable__()" メソッドを持っているかどうかチェックされます。

"Set" オブジェクトは、 "ImmutableSet" のインスタンスを返す
"__as_immutable__()" メソッドを持っているので、集合の集合を構築するこ
とが可能です。

集合内のメンバーであることをチェックするために、要素をハッシュする必要
がある "__contains__()" メソッドと "remove()" メソッドが、同様のメカニ
ズムを必要としています。これらのメソッドは要素がハッシュできるかチェッ
クします。もし出来なければ-- "__hash__()", "__eq__()", "__ne__()" のた
めの一時的なメソッドを備えたクラスによってラップされた要素を返すメソッ
ド-- "__as_temporarily_immutable__()" メソッドをチェックします。

代理メカニズムは、オリジナルの可変オブジェクトから分かれたコピーを組み
上げる手間を助けてくれます。

"Set" オブジェクトは、新しいクラス "_TemporarilyImmutableSet" によって
ラップされた "Set" オブジェクトを返す、
"__as_temporarily_immutable__()" メソッドを実装します。

ハッシュ可能を与えるための 2 つのメカニズムは通常ユーザーに見えません
。しかしながら、マルチスレッド環境下においては、
"_TemporarilyImmutableSet" によって一時的にラップされたものを持ってい
るスレッドがあるときに、もう一つのスレッドが集合を更新することで、衝突
を発生させることができます。言いかえれば、変更可能な集合の集合はスレッ
ドセーフではありません。


8.7.4. 組み込み "set" 型との比較
================================

組み込みの "set" および "frozenset" 型はこの "sets" で学んだことを生か
して設計されています。主な違いは次の通りです。

* "Set" と "ImmutableSet" は "set" と "frozenset" に改名されました。

* "BaseSet" に相当するものはありません。代わりに "isinstance(x,
  (set, frozenset))" を使って下さい。

* 組み込みのものに使われているハッシュアルゴリズムは、多くのデータ集
  合 に対してずっと良い性能 (少ない衝突) を実現します。

* 組み込みのものはより空間効率良く pickle 化できます。

* 組み込みのものには "union_update()" メソッドがありません。代わりに
  同 じ機能の "update()" メソッドを使って下さい。

* 組み込みのものには *_repr(sorted=True)* メソッドがありません。代わ
  り に組み込み関数の "repr()" と "sorted()" を使って
  "repr(sorted(s))" として下さい。

* 組み込みのものは変更不可能なものに自動で変換するプロトコルがありま
  せ ん。この機能は多くの人が困惑を覚えるわりに、コミュニティの誰から
  も実 際的な使用例の報告がありませんでした。
