10. 集合#

10.1. 基本#

集合はユニークな(重複のない)要素をまとめて保持する。「値」のない辞書と考えると分かりやすいかもしれない。

S = {'東京', '神奈川', '千葉', '埼玉'}
S
{'千葉', '埼玉', '東京', '神奈川'}
type(S)
set
len(S)
4

集合に要素が含まれているかどうかin演算子で調べることができる。

'東京' in S
True
'栃木' in S
False

集合に要素を追加するには、addメソッドを用いる。

S.add('栃木')
'栃木' in S
True

集合から要素を削除するには、removeメソッドを用いる。

S.remove('栃木')
'栃木' in S
False

集合の要素になっていないものをremoveメソッドで取り除こうとすると、エラーになる。

S.remove('栃木')
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/tmp/ipykernel_205042/85130292.py in <module>
----> 1 S.remove('栃木')

KeyError: '栃木'

集合の要素になっているときだけ削除するには、discardメソッドを用いる。

S.discard('栃木')

要素が空の集合(空集合)はset関数で作成する({}は辞書となってしまうため、集合とは異なるオブジェクトになってしまう)。

S = set()
S
set()

10.2. 集合の内包表記#

九九の3の段を表現する集合オブジェクトを作成してみる。

m3 = set()
for i in range(10):
    m3.add(i * 3)
m3
{0, 3, 6, 9, 12, 15, 18, 21, 24, 27}

このオブジェクトは、次のように集合の内包表記で構築することもできる。「i times 3 for all i in the range of ten」のように英語読みすると分かりやすいかもしれない。

m3n = {i*3 for i in range(10)}
m3n
{0, 3, 6, 9, 12, 15, 18, 21, 24, 27}

また、「0から29の範囲の中で3で割ったあまりが0になる数字の集合」というアイディアに基づいた実装をすると、以下のようになる。

m3nn = {i for i in range(30) if i % 3 == 0}
m3nn
{0, 3, 6, 9, 12, 15, 18, 21, 24, 27}

集合の内包表記をネストさせることで、九九で出てくる数字を表す集合を作成できる。

M = {i*j for j in range(10) for i in range(10)}
M
{0,
 1,
 2,
 3,
 4,
 5,
 6,
 7,
 8,
 9,
 10,
 12,
 14,
 15,
 16,
 18,
 20,
 21,
 24,
 25,
 27,
 28,
 30,
 32,
 35,
 36,
 40,
 42,
 45,
 48,
 49,
 54,
 56,
 63,
 64,
 72,
 81}

10.3. 集合間の演算#

\(1\)以上\(n\)以下の自然数を\(\mathbb{N}_n\)と書くことにする。\(1\)以上\(30\)以下の\(2\)の倍数と\(3\)の倍数を表す集合はそれぞれ、

\[\begin{split} M_2 = \{i \in \mathbb{N}_{30} \mid i \equiv 0 \pmod{2} \} \\ M_3 = \{i \in \mathbb{N}_{30} \mid i \equiv 0 \pmod{3} \} \end{split}\]

と書ける。\(\mathbb{N}_{30}\)\(M_2\)\(M_3\)をそれぞれ、集合型のオブジェクトNM2M3で表す。

N = set(range(1, 31))
M2 = {i for i in N if i % 2 == 0}
M3 = {i for i in N if i % 3 == 0}
M2
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}
M3
{3, 6, 9, 12, 15, 18, 21, 24, 27, 30}

\(M_2\)\(M_3\)の積集合\(M_2 \cap M_3\)&演算子で求められる。

M2 & M3
{6, 12, 18, 24, 30}

\(M_2\)\(M_3\)の和集合\(M_2 \cup M_3\)|演算子で求められる。

M2 | M3
{2, 3, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 26, 27, 28, 30}

\(\mathbb{N}_{30}\)\(M_2\)の差集合\(\mathbb{N}_{30} \setminus M_2\)-演算子で求められる。

N - M2
{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29}

\(M_2\)\(M_3\)のいずれか一方に含まれる要素を集めた集合は^演算子で求められる。

M2 ^ M3
{2, 3, 4, 8, 9, 10, 14, 15, 16, 20, 21, 22, 26, 27, 28}

2つの集合が部分集合の関係にあるかどうかは、<演算子で調べられる。

M2 < N
True
M2 < M3
False

2つの集合の要素が全て等しい/等しくないかは、==演算子および!=演算子で調べられる。

X = set(range(2, 31, 2))
X
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}
X == M2
True
X != M2
False
X == M3
False
X != M3
True