【Python】集合(set)でデータをフィルタリングする【入門第28回】

120, 2019-08-22

目次

集合(set)とは?

こんにちは、narupoです。

今回はPythonのデータ型の1つである集合(set)についてやりたいと思います。
集合を使うとリストやタプルから簡単に重複した要素を取り除くことができます

具体的には↓を見ていきます。

  • 集合の使い道

  • 集合の特徴

  • 集合の作り方

  • 集合の長さを得る(len)

  • 集合に要素を追加 (add)

  • 集合から要素を削除

  • 集合演算

  • 内包表記

  • リスト、タプルとの相互変換

集合はリストやタプルに比べると、出番の少ないデータ型かもしれません。
しかし、覚えておけばいざって時に使えますので、この記事で覚えておくといいかもしれません。

※ここに紹介してる集合の機能はいきなり全部を覚える必要はありません。

集合の使い道

集合は↓のようにして使います。

:::python
s = {1, 2, 3}

集合は重複した要素を持たないという特徴を持っているので、たとえば↓のようなリスト。

:::python
lst = [1, 1, 2, 2, 3, 3]

このリストから重複した要素を取り除きたい! となったときは↓のようにすると簡単に重複した要素を取り除けます。

:::python
s = set(lst)

集合はリストへ変換することができるので、↓のようにすれば再びリストにすることができます。

:::python
lst = list(s)

これで先ほどのリストから重複した要素を取り除くことができました。
まとめると↓のようなコードになります。

:::python
lst = [1, 1, 2, 2, 3, 3] # 重複した要素を持つリスト
s = set(lst) # リストを集合に変換
lst = list(s) # 集合をリストに変換
print(lst) # リストを出力

↑のコードの実行結果は↓のようになります。

:::python
[1, 2, 3]

集合の特徴

集合は↓のような特徴を持っています。

  • 重複した要素を持たない

  • 順序を持たない

重複した要素を持たないので、↓のようにすると重複した値は取り除かれます。

:::python
s = {1, 1, 2, 2, 3, 3}

さらに集合は順序を持ちません。
なので、↓のように値を並べても集合をその並び方を維持しません。

:::python
s = {4, 2, 3, 1}

集合の作り方

集合を作るには↓のように波括弧({}を使います。

:::python
{1, 2, 3}

値はカンマ(,)で区切って複数入れることができます。
同じ値を重複して入れても、集合からは重複した値は取り除かれます。

:::python
print({1, 1, 2, 2, 3, 3})

↑のコードの実行結果は↓のようになります。

{1, 2, 3}

また、↓のようにして値の並びを維持したくても、集合は値の並びを無視します。

:::python
print({4, 3, 1, 2})

↑のコードの実行結果は↓のようになります。

{1, 2, 3, 4}

空の集合を作りたい場合は↓のようにしたいところですが、

:::python
{}

ざんねんながら、↑は集合ではなく辞書というデータ型になります。
空の集合を作るには↓のようにsetクラスを使います。

:::python
set()

このsetクラスはリストやタプルとの相互変換で活躍します。
集合は↓のように変数に入れることができます。

:::python
s = {1, 2, 3}

集合の長さを得る(len)

集合の長さを得るにはlen関数を使います。

:::python
s = {1, 2, 3}
print(len(s))

↑のコードの実行結果は↓のようになります。

3

集合に要素を追加 (add)

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

:::python
s = {1, 2, 3}
s.add(4)
print(s)

↑のコードの実行結果は↓のようになります。

{1, 2, 3, 4}

集合から要素を削除

集合から要素を削除するには↓のメソッドを使います。

  • discard

  • remove

  • pop

  • clear

discard

discardメソッドは引数の値の要素を集合から削除します。

:::python
s = {1, 2, 3}
s.discard(2)
print(s)

↑のコードの実行結果は↓のようになります。

{1, 3}

discardは引数の値の要素が集合に無かった場合は、なにもしません。

:::python
s = {1, 2, 3}
s.discard(8)

remove

removeメソッドも引数の値の要素を集合から削除します。

:::python
s = {1, 2, 3}
s.remove(2)
print(s)

↑のコードの実行結果は↓のようになります。

{1, 3}

removeメソッドは引数の値の要素が集合に無かった場合はKeyErrorになります。

:::python
s = {1, 2, 3}
s.remove(8)

↑のコードの実行結果は↓のようになります。

KeyError: 8

pop

popメソッドは集合から不特定の値の要素を削除し、その値を返します。

:::python
s = {1, 2, 3}
el = s.pop()
print(el)

↑のコードの実行結果は↓のようになります。

1

削除する要素は選択できません。
また、空集合で実行するとKeyErrorになります。

:::python
s = set()
s.pop()

↑のコードの実行結果は↓のようになります。

KeyError: 'pop from an empty set'

clear

集合を空にするにはclearメソッドを使います。

:::python
s = {1, 2, 3}
s.clear()
print(s)

↑のコードの実行結果は↓のようになります。

set()

集合演算

集合を集合とたらしめる便利な演算が集合にはあります。
この演算を使えると、集合に対していろいろなフィルタリングができるようになります。

フィルタリングしちゃおうね~

和集合

和集合を取得するには|演算を使います。

:::python
s1 = {1, 2}
s2 = {2, 3}

s3 = s1 | s2

print(s3)

↑のコードの実行結果は↓のようになります。

{1, 2, 3}

この演算は、単純に集合同士の足し算です。
↑の例ではs1s2の集合を足したものがs3に代入されます。
そのさい、重複する値(2)は集合から取り除かれます。

また、unionメソッドを使っても和集合の演算をすることができます。
unionメソッドはリストやタプルも演算することが可能です。

:::python
s1 = {1, 2}
lst = [2, 3]

s3 = s1.union(lst)

print(s3)

↑のコードの実行結果は↓のようになります。

{1, 2, 3}

差集合

差集合は-演算子で取得することができます。

:::python
s1 = {1, 2, 3, 4}
s2 = {3, 4}

s3 = s1 - s2

print(s3)

↑のコードの実行結果は↓のようになります。

{1, 2}

-演算子は左項から右項の値を取り除きます。
単純に引き算ですね。
s1には1, 2, 3, 4の値が入っていて、s2には3, 4の値が入っています。
よってs1 - s2とするとs1から3, 4の値が取り除かれます。
よって結果は{1, 2}になります。

差集合はdifferenceメソッドを使うことでも演算できます。
このメソッドを使う場合はリストやタプルとも演算できます。

:::python
s1 = {1, 2, 3, 4}
lst = [3, 4]

s3 = s1.difference(lst)

print(s3)

↑のコードの実行結果は↓のようになります。

{1, 2}

積集合

積集合は&演算子で取得できます。

:::python
s1 = {1, 2}
s2 = {2, 3}

s3 = s1 & s2

print(s3)

↑のコードの実行結果は↓のようになります。

{2}

積集合は、両方の集合に含まれている要素を取り出します。
s1には2があって、s2にも2があるので、これらを&で演算すると2が取り出せるということですね

intersectionメソッドを使えばリストやタプルとも演算できます。

:::python
s1 = {1, 2}
lst = [2, 3]

s3 = s1.intersection(lst)

print(s3)

↑のコードの実行結果は↓のようになります。

{2}

対象差集合

対象差集合を取得するには^演算子を使います。

:::python
s1 = {1, 2}
s2 = {2, 3}

s3 = s1 ^ s2

print(s3)

↑のコードの実行結果は↓のようになります。

{1, 3}

^演算子は両方の集合に含まれていない要素を取り出します。
たとえばs1の要素1s2には含まれていません。
そしてs2の要素3s1には含まれていません。
しかし要素2は両方の集合に含まれています。
よって演算では{1, 3}が取り出せます。

symmetric_differenceメソッドを使えばリストやタプルとも演算できます。

:::python
s1 = {1, 2}
lst = [2, 3]

s3 = s1.symmetric_difference(lst)

print(s3)

↑のコードの実行結果は↓のようになります。

{1, 3}

メソッド名、長いな~

部分集合

ある集合がある集合の部分集合かどうかを判定するには<=演算子を使います。

:::python
s1 = {1, 2}
s2 = {1, 2, 3, 4}

print(s1 <= s2)

↑のコードの実行結果はTrueになります。

s1s2の部分集合、つまりs1の要素すべてがs2に含まれているので、演算ではTrueになります。
含まれていない場合はどうなるのでしょうか?

:::python
s1 = {1, 9}
s2 = {1, 2, 3, 4}

print(s1 <= s2)

↑のコードの実行結果はFalseになります。
s1s2の部分集合ではない、つまりs1の要素がすべてs2に含まれていないからですね。

issubsetメソッドを使えばリストやタプルとも演算できます。

:::python
s1 = {1, 2}
lst = [1, 2, 3, 4]

print(s1.issubset(lst))

s1lstのサブセット(部分集合)なので↑のコードの実行結果はTrueになります。

上位集合

ある集合がある集合の上位集合か判定するには>=演算子を使います。

:::python
s1 = {1, 2, 3, 4}
s2 = {1, 2}

print(s1 >= s2)

↑のコードの実行結果はTrueになります。
s1にはs2の要素がすべて含まれているからですね。

:::python
s1 = {1, 2, 3, 4}
s2 = {1, 9}

print(s1 >= s2)

↑のコードの実行結果はFalseになります。
s1にはs2の要素がすべて含まれていないからです。

issupersetメソッドを使えばリストやタプルとも演算できます。

:::python
s1 = {1, 2, 3, 4}
lst = [1, 2]

print(s1.issuperset(lst))

↑のコードの実行結果はTrueになります。

互いに素か

isdisjointを使うと2つの集合が互いに素かどうか判定できます。

:::python
s1 = {1, 2}
s2 = {3, 4}

print(s1.isdisjoint(s2))

↑のコードの実行結果はTrueになります。
s1の要素はs2に含まれていないし、s2の要素はs1に含まれていないからですね。

:::python
s1 = {1, 2}
s2 = {2, 3}

print(s1.isdisjoint(s2))

↑のコードの実行結果はFalseになります。
要素2が互いの集合に含まれているので、互いに素ではないからです。

内包表記

集合をfor文などのループを使って作りたい時、集合の内包表記というのが使えます。
↓のようにします。

:::python
{i for i in range(4)}

↑を実行すると↓のような集合が作られます。

{0, 1, 2, 3}

これは↓のコードと等価です。

:::python
s = set()
for i in range(4):
    s.add(i)

内包表記はかっちょいい

リスト、タプルとの相互変換

集合をリストやタプルなどと相互変換したい場合は、setクラスやlistクラスを使います。
リストを集合にするには↓のようにします。

:::python
lst = [1, 2, 3]
s = set(lst)

集合をリストにするには↓のようにします。

:::python
s = {1, 2, 3}
lst = list(s)

タプルを集合にするには↓のようにします。

:::python
tpl = (1, 2, 3)
s = set(tpl)

集合をタプルにするには↓のようにします。

:::python
s = {1, 2, 3}
tpl = tuple(s)

おわりに

集合を使えると、重複した要素の取り除きや、抽出に使えます。
これらの処理をfor文などで書こうとすると、けっこうめんどくさいものです。
そういったときは集合の存在を思い出してみてください。

以上、次回に続きます。

また見てね

関連動画