1 リスト内包表記 (List Comprehensions)

リスト内包表記 (list comprehension) は、“Python”言語でリストを作成する簡潔な方法です。既存のリスト、タプル、セット、または文字列などのイテラブルの各要素に式 (expression) を適用して新しいリストを生成することができます。また条件に基づいて要素をフィルタリングすることも可能です。

1.1 リスト内包表記の基本的な使い方

リスト内包表記の基本的な構造を Tip 1 に示します.

Tip 1: TIPS

new_list = [expression for item in iterable]
  • iterable: リストやタプルなどのオブジェクト

このリスト内包表記の構造については深く考えないでください。これから説明を進めていきます。

リスト内包表記がどのように機能するかを、例を使って確認してみましょう:

# Using list comprehension to achieve the same result in a more concise way
squares = [i**2 for i in range(1, 11)]
print(squares)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

各コードの説明を以下に示します:

for i in range(1, 11): この部分では、1から10まで(両端を含む)の数字を繰り返し処理するループが設定されています。各反復では、iというループ変数が1、2、3、、、10という値を取ります。

i**2: これは反復処理中の各iの値に適用される式です。iの2乗が計算されます。

[i**2 for i in range(1, 11)]: このコード全体がリスト内包表記を表しています。新しいリストを生成し、1から10までの各数の2乗が要素となります。

したがって、squares = [i**2 for i in range(1, 11)] を実行するとsquaresという名前のリストが作成され、その要素は 1 から 10 の数字の2乗となります。結果として得られるリストは [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]です。

上記のsquaresリストをリスト内包表記なしで作成することもできますが、少し長くなります:

# Create a list of squares of numbers from 1 to 10 using a for loop
squares = []
for i in range(1, 11):
    squares.append(i**2)
print(squares)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

1.2 リスト内包表記をフィルターと操作に利用する

特定の条件に基づいて要素をフィルタリングするために、リスト内包表記内で条件式を使用することもできます。例えば:

# 条件を加えたリスト内包表記の使用
evens = [i for i in range(1, 11) if i % 2 == 0]
print(evens)
[2, 4, 6, 8, 10]

iが偶数の場合、その値がリストに追加されます。その他の場合は条件式は何も返しません。つまり、if i % 2 == 0 はフィルターのように機能します。

同じリストを通常のループで生成することもできますが、リスト内包表記の方が簡潔なため適切な方法です:

# forループを使って1から10の範囲における偶数のリストを作成する
evens = []
for i in range(1, 11):
    if i % 2 == 0:
        evens.append(i)
print(evens)
[2, 4, 6, 8, 10]

次の例では score に基づいて成績を出力するという操作を行ってみましょう。リスト内包表記ではif文と一緒にelse文を使用することもできますが、elif文を利用することはできません。

# リスト内包表記でif-else文を使用する例
grades = ["A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "D" if score >= 60 else "E" for score in [85, 77, 92, 60, 45]]
print(grades)
['B', 'C', 'A', 'D', 'E']

上記のコードでは、 [85, 77, 92, 60, 45] を取り、値が90以上の場合は"A"を返します。それ以外で値が80以上なら"B"を返します。以下同様です。

条件式の構造を説明するために、上記のコードを通常のループを使って書き直します:

# リスト内包表記
# -> "elif"文がない通常のループ
scores = [85, 77, 92, 60, 45]
grades = []

for score in scores:
    if score >= 90:
        grades.append("A")
    else:
        if score >= 80:
            grades.append("B")
        else:
            if score >= 70:
                grades.append("C")
            else:
                if score >= 60:
                    grades.append("D")
                else:
                    grades.append("E")

# 最終的な成績のリストを出力する
print(grades)
['B', 'C', 'A', 'D', 'E']

上記のコードからわかるように、ネストされた ifelse 文を使っています。これらの条件は以下と同様です:

# "elif"文がない通常のループ
# -> "elif"文がある通常のループ
scores = [85, 77, 92, 60, 45]
grades = []

for score in scores:
    if score >= 90:
        grades.append("A")
    elif score >= 80:
        grades.append("B")
    elif score >= 70:
        grades.append("C")
    elif score >= 60:
        grades.append("D")
    else:
        grades.append("E")

# 最終的な成績のリストを出力する
print(grades)
['B', 'C', 'A', 'D', 'E']

リスト内包表記の中でのifelse構造が難しいと感じたら、ヘルパー関数を使用することができます。次のコードでは、convert_to_grade()がヘルパー関数です(*「関数」については次の記事で説明します)。複雑な条件や操作をカプセル化させ、独立した関数を定義し、それをリスト内包表記の中で呼び出すことができます。

# リスト内包表記のためのヘルパー関数
def convert_to_grade(score):
    if score >= 90:
        return "A"
    elif score >= 80:
        return "B"
    elif score >= 70:
        return "C"
    elif score >= 60:
        return "D"
    else:
        return "E"

scores = [85, 77, 92, 60, 45]
grades = [convert_to_grade(score) for score in scores]
print(grades)
['B', 'C', 'A', 'D', 'E']

この方が、ずっと理解しやすく見えます。

したがって、リスト内包表記は値をフィルタリングしたり、操作して新しいリストを作成する簡潔な方法であると言えます。

TIPS

リスト内包表記を使って新しいリストを作ることができます。また以下のことを行えます:

  • 値をフィルタリングする
  • 値を操作する

2 Exercises