Python 3でのリスト内包表記の理解

紹介

リスト内包表記は、既存のリストに基づいてリストを簡潔に作成する方法を提供します。リスト内包表記を使用すると、リストだけでなく、イテラブル、つまり文字列タプルを活用してリストを構築することができます。

構文上、リスト内包表記は式を含むイテラブルに続くfor句で構成されます。これには追加のfor句やif句が続くことがあり、forループ条件文に精通しているとリスト内包表記を理解するのに役立ちます。

リスト内包表記は、リストやその他の順序付けられたデータ型を作成するための代替構文を提供します。他の反復の方法であるforループなどを使用してリストを作成することもできますが、プログラムで使用される行数を制限できるため、リスト内包表記が好まれる場合があります。

前提条件

Python 3がインストールされ、コンピューターまたはサーバーにプログラミング環境が設定されている必要があります。プログラミング環境が設定されていない場合は、お使いのオペレーティングシステム(Ubuntu、CentOS、Debianなど)に適したローカルプログラミング環境またはサーバー上のプログラミング環境のインストールおよび設定ガイドを参照してください。

リスト内包表記

Pythonでは、リスト内包表記は次のように構築されます:

情報: このチュートリアルの例コードに従うには、python3コマンドを実行してローカルシステム上でPythonインタラクティブシェルを開きます。その後、>>>プロンプトの後にそれらを追加することで、例をコピー、貼り付け、または編集できます。

list_variable = [x for x in iterable]

A list, or other iterable, is assigned to a variable. Additional variables that stand for items within the iterable are constructed around a for clause. The in keyword is used as it is in for loops, to iterate over the iterable.

次は、文字列に基づいてリストを作成する例を見てみましょう。

shark_letters = [letter for letter in 'shark']
print(shark_letters)

ここでは、新しいリストが変数shark_lettersに割り当てられ、letterが反復可能な文字列'shark'に含まれるアイテムを表すために使用されています。

新しいリストshark_lettersの外観を確認するために、それをprint()して次の出力を受け取ります。

Output
['s', 'h', 'a', 'r', 'k']

リスト内包表記で作成したリストは、文字列'shark'のアイテムで構成されています。つまり、各文字に1つの文字列です。

リスト内包表記はforループとして書き直すことができますが、すべてのforループがリスト内包表記として書き直すことができるわけではありません。

上記のshark_lettersリストを作成したリスト内包表記をforループとして書き直してみましょう。これにより、リスト内包表記がどのように機能するかをよりよく理解できるかもしれません。

shark_letters = []

for letter in 'shark':
    shark_letters.append(letter)

print(shark_letters)

forループでリストを作成する場合、リストに割り当てられる変数は空のリストで初期化する必要があります。これは、コードブロックの最初の行で行われています。そして、forループは、反復可能な文字列'shark'内の変数letterを使用して反復します。 forループ内では、文字列内の各アイテムがlist.append(x)メソッドを使ってリストに追加されます。

リスト内包表記をforループとして書き直すと、同じ出力が得られます:

Output
['s', 'h', 'a', 'r', 'k']

リスト内包表記はforループとして書き直すことができ、一部のforループはリスト内包表記に書き直すことができ、コードをより簡潔にすることができます。

リスト内包表記で条件文を使用する

リスト内包表記は、新しいリストを作成する際に既存のリストやその他の順次データ型を修正するために条件文を利用することができます。

条件文を使用したリスト内包表記の例を見てみましょう:if文がリスト内包表記で使用されている例を見てみましょう。

fish_tuple = ('blowfish', 'clownfish', 'catfish', 'octopus')

fish_list = [fish for fish in fish_tuple if fish != 'octopus']
print(fish_list)

リスト内包表記は、タプルfish_tupleを基にしてfish_listという新しいリストを作成します。 forおよびinのキーワードが使用されており、これらは上記のセクションで使用されたものと同じです。そして今、ifステートメントが追加されます。 ifステートメントでは、文字列'octopus'と等しくないアイテムのみを追加するように指示されています。したがって、新しいリストは、'octopus'と一致しないタプルのアイテムのみを受け入れます。

これを実行すると、fish_listには'octopus'の文字列を除いてfish_tupleと同じ文字列が含まれていることがわかります:

Output
['blowfish', 'clownfish', 'catfish']

したがって、新しいリストには、条件文によって除外された文字列を除く、元のタプルのすべてのアイテムが含まれています。

次に、数学演算子整数、およびrange()シーケンス型を使用した別の例を作成します。

number_list = [x ** 2 for x in range(10) if x % 2 == 0]
print(number_list)

作成されるリストnumber_listは、0から9の範囲の各アイテムの二乗値で構成され、アイテムの値が2で割り切れる場合に限ります。出力は以下の通りです:

Output
[0, 4, 16, 36, 64]

リスト内包表記が行っていることをもう少し詳しく説明しましょう。たとえば、単にx for x in range(10)を呼び出している場合、出力は以下のようになります:

number_list = [x for x in range(10)]
print(number_list)
Output
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

次に、条件文を追加しましょう:

number_list = [x for x in range(10) if x % 2 == 0]
print(number_list)
Output
[0, 2, 4, 6, 8]

このif文は、最終リスト内のアイテムを偶数のみに限定し、すべての奇数を省略します。

最後に、各xを二乗する演算子を追加できます:

number_list = [x ** 2 for x in range(10) if x % 2 == 0]
print(number_list)

したがって、前の[0, 2, 4, 6, 8]のリスト内の各数字が二乗されます:

Output
[0, 4, 16, 36, 64]

また、リスト内包表記でネストされたifを再現することもできます:

number_list = [x for x in range(100) if x % 3 == 0 if x % 5 == 0]
print(number_list)

ここでは、リスト内包表記はまず数字xが3で割り切れるかどうかをチェックし、次にxが5で割り切れるかどうかをチェックします。もしxが両方の要件を満たしていれば、出力されます。結果は以下の通りです:

Output
[0, 15, 30, 45, 60, 75, 90]

条件付きif文は、既存のシーケンスから新しいリストの作成に含まれるアイテムを制御するために使用できます。

リスト内包表記内のネストされたループ

入れ子のループを使用して、プログラム内で複数の繰り返しを実行できます。

今回は、既存の入れ子のforループ構造を見直し、リスト内包表記に進んでみましょう。

次のコードは、2つのリストを繰り返し処理し、それらに基づいて数学的な操作を行う新しいリストを作成します。以下は、入れ子のforループのコードブロックです:

my_list = []

for x in [20, 40, 60]:
	for y in [2, 4, 6]:
		my_list.append(x * y)

print(my_list)

このコードを実行すると、次の出力が得られます:

Output
[40, 80, 120, 80, 160, 240, 120, 240, 360]

このコードは、各繰り返しで最初のリストのアイテムを2番目のリストのアイテムで乗算しています。

これをリスト内包表記に変換するには、各コード行を1行にまとめます。最初にx * y操作が来ます。これに続いて外側のforループ、そして内側のforループが続きます。そして、print()ステートメントをリスト内包表記の下に追加して、新しいリストが上記の入れ子のforループブロックで作成したリストと一致することを確認します:

my_list = [x * y for x in [20, 40, 60] for y in [2, 4, 6]]
print(my_list)
Output
[40, 80, 120, 80, 160, 240, 120, 240, 360]

リスト内包表記は、入れ子のforループを1行のコードにまとめ、まだmy_list変数に割り当てる正確な同じリストを作成します。

リスト内包表記は、複数の行のコードを1行にまとめる簡潔な方法を提供しますが、コードの可読性が常に優先されるべきだということを念頭に置いておくことが重要です。そのため、リスト内包表記の行が長すぎるか扱いにくい場合は、ループに分割するのが最善です。

結論

リスト内包表記は、1つのリストや他のシーケンスを新しいリストに変換することを可能にします。このタスクを完了するための簡潔な構文を提供し、コードの行数を制限します。

リスト内包表記は、集合ビルダー表記または集合内包表記の数学的形式に従うため、数学的なバックグラウンドを持つプログラマーにとって特に直感的かもしれません。

リスト内包表記はコードをより簡潔にすることができますが、最終的なコードが可能な限り読みやすいことを確認することが重要です。そのため、非常に長い単一行のコードは避けるべきで、コードがユーザーフレンドリーであることを確認する必要があります。

Source:
https://www.digitalocean.com/community/tutorials/understanding-list-comprehensions-in-python-3