
:mod:`sets` --- ユニークな要素の順序なしコレクション
====================================================

.. module:: sets
   :synopsis: ユニークな要素の集合の実装
   :deprecated:
.. moduleauthor:: Greg V. Wilson <gvwilson@nevex.com>
.. moduleauthor:: Alex Martelli <aleax@aleax.it>
.. moduleauthor:: Guido van Rossum <guido@python.org>
.. sectionauthor:: Raymond D. Hettinger <python@rcn.com>


.. versionadded:: 2.3

.. deprecated:: 2.6
   組み込みの :class:`set`/:class:`frozenset` 型がこのモジュールを置き換えます。

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

他のコレクションのように、 ``x in set``, ``len(set)``, ``for x in set`` をサポートします。
順序なしコレクションは、挿入の順序や要素位置を記録しません。
従って、インデックス・スライス・他のシーケンス的な振舞いをサポートしません。

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

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


.. class:: Set([iterable])

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


.. class:: ImmutableSet([iterable])

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

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


.. _set-objects:

Set オブジェクト
----------------

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

+-------------------------------+------------+---------------------------------------------------+
| 演算                          | 等価な演算 | 結果                                              |
+===============================+============+===================================================+
| ``len(s)``                    |            | 集合 *s* の濃度 (cardinality)                     |
+-------------------------------+------------+---------------------------------------------------+
| ``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* の浅いコピーからなる集合                      |
+-------------------------------+------------+---------------------------------------------------+

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

.. versionchanged:: 2.3.1
   以前は全ての引数が集合型でなければなりませんでした。

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

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

集合は一部の順序（部分集合の関係）を定義するだけなので、集合のリストにおいて :meth:`list.sort` メソッドの出力は未定義です。

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

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

以下は :class:`Set` で利用可能であるが :class:`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* がなければ :exc:`KeyError` を送出します         |
+--------------------------------------+-------------+-----------------------------------------------------+
| ``s.discard(x)``                     |             | 要素 *x* が存在すれば、集合 *s* から取り除きます    |
+--------------------------------------+-------------+-----------------------------------------------------+
| ``s.pop()``                          |             | *s* から要素を取り除き、それを返します;             |
|                                      |             | 集合が空なら :exc:`KeyError` を送出します           |
+--------------------------------------+-------------+-----------------------------------------------------+
| ``s.clear()``                        |             | 集合 *s* からすべての要素を取り除きます             |
+--------------------------------------+-------------+-----------------------------------------------------+

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

.. versionchanged:: 2.3.1
   以前は全ての引数が集合型でなければなりませんでした。

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


.. _set-example:

使用例
------

   >>> 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.union_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'])


.. _immutable-transforms:

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

集合は変更不可能な要素だけを含むことできます。都合上、変更可能な :class:`Set` オブジェクトは、集合要素として加えられる前に、
自動的に :class:`ImmutableSet` へコピーします。そのメカニズムはハッシュ可能な(:term:`hashable`)要素を常に加えることですが、
もしハッシュ不可能な場合は、その要素は変更不可能な等価物を返す :meth:`__as_immutable__` メソッドを持っているかどうかチェックされます。

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

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

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

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

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


.. _comparison-to-builtin-set:

組み込み :class:`set` 型との比較
--------------------------------

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

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

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

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

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

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

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

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

