Developer

【Python独学】セットの内包表記
2020.11.02
Lv1

【Python独学】セットの内包表記

今回は、セット(集合)の内包表記について、以下のようにみていきましょう。

  • 内包表記について
  • セット型の内包表記

内包表記について

内包表記の基本と特徴について、順番に確認していきます。

・内包表記の基本
・if文との組み合わせ
・内包表記の利点


内包表記の基本

内包表記とは、Pythonの特徴的な記述方法の一つです。イテラブルなオブジェクトから要素を1つずつ取り出し、
取り出した値を式で評価し、得られた結果を要素とする新しいリストを作成します。

リストを扱った際に、リスト内包表記が出てきたかと思います。
リスト内包表記は以下のように記述しました。

[式 for 変数 in イテラブルなオブジェクト]

リストやタプルなどのイテラブルなオブジェクトが持っている要素を一つずつ取り出し、変数に入れていきます。
そして、取り出した変数を使って手前の式を実行し、その結果を新しいリストの要素として加えていきます。

例をみてみましょう。

list_num = list(range(5))          ### range()でリストの要素を作成
print(list_num)

num2 = [i * 2 for i in list_num]   ### リスト内包表記でlist_numの要素を2倍したリストを作成

print(num2)
C:\Python> python 9-4_1.py
[0, 1, 2, 3, 4]      ### list_numの要素
[0, 2, 4, 6, 8]      ### list_numの各要素を2倍した要素を持つnum2

上記の例では、はじめに作成した0~4までの数字を要素として持つlist_numに対し、
リスト内包表記でその要素を1つずつ取り出し、2倍しています。
そして、2倍した値を要素として持つ新しいリストnum2を作成しました。

こういった要素の取り出しと式の評価を内包表記を使わずに記述するには、for文を使って記述する必要があります。
のちほど比較してみましょう。

if文との組み合わせ

以下のようにif文を組み合わせることもできます。

nums_odd = [i for i in range(10) if i % 2 == 1]

print(nums_odd)
C:\Python> python 9-4_2.py
[1, 3, 5, 7, 9]      ### 奇数だけが取り出されている

上記の例では、range(10)で作成した0~9の値の中で、後ろで記述したif文の結果がTrueになるもののみ
nums_oddの要素としてリストを作成しています。
このように、内包表記では取り出した値を要素にする前に、if文で条件判定を行うことも可能です。

内包表記の利点

Pythonの内包表記の利点としてよく挙げられるのが以下のような内容です。

・コードがスッキリする(わかりやすくなるかは別問題)
・実行速度が早くなる

後者の実行速度については少々ややこしい話になるので割愛しますが、for文を用いて処理を記述した場合と、
内包表記を使って同じ処理を記述した場合では、内包表記のほうが処理の実行速度が早くなると言われています。

前者の利点については、同じ処理を記述したものを見比べてみるとわかるかと思います。
以下は、for文を使って記述した場合と内包表記を使って同じ処理を記述した場合の比較になります。

for文の場合

num = list(range(5))
nums = []

for i in num:
	nums.append(i*2)

print(nums)

内包表記の場合

nums = [i*2 for i in range(5)]

print(nums)

実行結果はどちらも同じものになります。

C:\Python> python 9-4_3.py
[0, 2, 4, 6, 8]

このように、同じ処理であれば内包表記のほうが比較的コードの量が減り、すっきりします。
ただし、Pythonの内包表記は書き方が特徴的なので、Pythonに慣れた人であればわかりやすくみえるかもしれませんが、
他言語に慣れた方が見たときに少しわかりづらく感じることもあるかもしれませんので、注意が必要です。


セット型の内包表記

セット型でも内包表記の記述は基本的に変わりません。
リスト内包表記の [] を {} に変えると、セット型のオブジェクトが作成されるようになります。

{式 for 変数 in イテラブルなオブジェクト}

では、実際に記述してみましょう。

set_num2 = {i * 2 for i in range(5)}   ### range型オブジェクトをイテラブルとして与えている

print(set_num2)
print(type(set_num2))
C:\Python> python 9-4_4.py
{0, 2, 4, 6, 8}
<class ‘set’>

出力とtype()の結果から、作成されたオブジェクトがセット型であることが確認できました。
出来上がるものがセット型であるだけなので、リスト内包表記と同じように使うことができます。
イテラブルなオブジェクトにリストやタプル、上記の例のようにrange型を与えることもできますし、
if文と組み合わせたりするような書き方もできます。


まとめ

・内包表記は通常のfor文に対していくつかの利点のある記述の仕方である
・セット型の内包表記は {} で記述する


確認問題

以下のfor文を内包表記を用いて1文で記述してみましょう。

set_num = set(range(10))
nums = set()

for i in set_num:
	if i % 2 == 0:
		nums.add(i**2)

print(nums)
C:\Python> python 9-4_question.py
{0, 64, 4, 36, 16}

答えはこちらの記事の最後に!
【Python連載】集合演算子と演算メソッド


前回の確認問題の回答例

前回の記事はこちら→【Python連載】セットの操作&frozenset型について

前回はこんな問題でした。

以下の選択肢の中で、正しいものを全て選びましょう。

1.sorted() は、set型で定義されているメソッドである。
2.set型もリスト等と同じようにイテラブルなオブジェクトである。
3.frozenset型は、要素の追加削除を行うことができない。
4.frozenset型のオブジェクトは、set型の要素に含めることができる。

それでは、順番に確認していきましょう。

1.sorted() は、set型で定義されているメソッドである。
→これは×です。sorted()はオブジェクトに紐付いたメソッドではなく、Pythonがもともと持っている組み込み関数です。
 同じように並び替えを行うsortメソッドは、リスト型のメソッドです。

2.set型もリスト等と同じようにイテラブルなオブジェクトである。
→これはです。イテラブルとは、反復可能、簡単に言うと要素を1つずつ取り出せるもののことであり、
リストやタプル、セットなどはイテラブルなオブジェクトです。

3.frozenset型は、要素の追加削除を行うことができない。
→これはです。frozenset型は通常のset型と異なり、イミュータブルなオブジェクトなので、
要素の追加削除などを行うことはできません。

4.frozenset型のオブジェクトは、set型の要素に含めることができる。
→これはです。frozenset型はイミュータブルなオブジェクトなので、set型の要素として成立します。
 例をみてみましょう。

frozen = frozenset(range(3))     ### frozenset型のオブジェクトを作成

set_test = {100,200,frozen}      ### set型を作成する際に、要素として上で作成したfrozenを含める

print(frozen)
print(set_test)
C:\Python> python 9-4_answer.py
frozenset({0, 1, 2})
{200, 100, frozenset({0, 1, 2})}
このように、frozenset型のオブジェクトはset型の要素に含めることができます。

なので、正しい選択肢は 2,3,4 となります。

連載目次

独学で学ぶ Pythonプログラミング 連載目次