Python入門
第17回.リスト内包表記

Pythonの初心者向け入門解説、人気のプログラミング言語Python
最終更新日:2020-09-27

第17回.リスト内包表記


Python リスト内包表記

Pythonではリストを生成する方法の1つとしてリスト内包表記があります。
リスト内包表記を使うと1行でシンプルに書くことが出来ます。


Pythonではシンプルかつ効率的な記述方法として良く利用されています。
ただし分かりづらいところがあり慣れが必要だと思います。
繰り返し練習が必要になると思うので、以下ではスクリプトをコピーして簡単に実行できるようにしました。


目次

リスト内包表記の基本

Pythonのリスト生成方法の1つにリスト内包表記があり、リスト生成をシンプルに書くことが出来ます。
公式ドキュメント - 5.1.3. リストの内包表記

基本構文

リスト変数 = [式 for 変数 in イテラブル]
イテラブル(シーケンス等のイテラブルオブジェクト)から要素を1つずつ取り出し、
式で評価した結果でリスト生成します。
上記は次のfor文と互換になります。
リスト変数 = []
for 変数 in イテラブル:
    リスト変数.append(式)

以下は0から4のシーケンスを2倍した数値でリスト生成しています。
ary = [i * 2 for i in range(5)]
print(ary)
Python リスト内包表記

rangeから0~4の数値が順次 i に取り出されて、2倍した結果でリスト生成されます。

これを普通にfor文で書いた場合は、
ary = []
for i in range(5):
    ary.append(i * 2)
print(ary)
行数も1行でシンプルになるという利点はもちろんありますが、
変数 i のスコープが内包表記内に閉じている点も大きい利点です。

Python リスト内包表記

他に影響(間違った変数書換等)を与えずにリスト生成できることは非常に便利です。
上記はlambda(ラムダ式)で書くこともできます。
ary = list(map(lambda n:n * 2, range(5)))
print(ary)


リスト内包表記の条件分岐

リスト内包表記の中で条件分岐させる場合は、for inの後にif文を記述します。

基本構文

リスト変数 = [式 for 変数 in イテラブル if 条件式]
後置if形式になります。
イテラブル(シーケンス等のイテラブルオブジェクト)から要素を1つずつ取り出し、
条件式がTrueの値だけを最初の式で評価しリスト生成します。
これは次のfor文と互換になります。
リスト変数 = []
for 変数 in イテラブル:
    if 条件式:
        リスト変数.append(式)
print(subs)
print(ary)

文字列の一部に"a"or"A"の文字を含むもの

lang = ["Python","VBA","GAS","Java","C","JavaScript"]
subs = [s for s in lang if "a" in s.lower()]
print(subs)
Python リスト内包表記

リストから1要素ずつ取り出された文字列がsに入ります。
s.lower()で小文字に変換した結果の文字列に"a"が入っていればTrue。
Trueの場合だけリスト生成されます。

これを普通にfor文で書いた場合は、
lang = ["Python","VBA","GAS","Java","C","JavaScript"]
subs = []
for s in lang:
    if "a" in s.lower():
        subs.append(s)
print(subs)
上記はlambda(ラムダ式)で書くこともできます。
lang = ["Python","VBA","GAS","Java","C","JavaScript"]
subs = filter(lambda s:s if "a" in s.lower() else None, lang)
print(list(subs))
ラムダ式については以下を参照してください。
第15回.lambda(ラムダ式、無名関数)と三項演算子
関数は一連の処理をまとめることで再利用可能にした、プログラム内の小さなプログラムのようなものです。Pythonでの関数の記述方法としてlambda(ラムダ式、無名関数)があります。lambdaは無名関数を定義するものです。

3の倍数だけ抜き出す

#リスト内包表記
ary = [i for i in range(1,11) if i % 3 == 0]
print(ary)
Python リスト内包表記

#for文
ary = []
for n in range(1, 11):
    if n % 3 == 0:
        ary.append(n)
print(ary)
#ラムダ式とfilter()関数
ary = list(filter(lambda i:i if i % 3 == 0 else None, range(1,11)))
print(ary)
ラムダ式とfilter()関数については以下を参照してください。

3の倍数は3倍、以外は2倍

#リスト内包表記
ary = [i * 3 if i % 3 == 0 else i * 2 for i in range(1,11)]
print(ary)
Python リスト内包表記

#for文
ary = []
for n in range(1,11):
    if n % 3 == 0:
        ary.append(n * 3)
    else:
        ary.append(n * 2)
print(ary)
#ラムダ式とmap関数
ary = list(map(lambda i:i * 3 if i % 3 == 0 else i * 2, range(1,11)))
print(ary)
ラムダ式とmap()関数については以下を参照してください。

リスト内包表記の複数for文

基本構文

リスト変数 = [式 for 変数1 in イテラブル1 for 変数2 in イテラブル2]
横に長くなってしまう場合は適宜改行してください。
リスト変数 = [式 for 変数1 in イテラブル1 
                    for 変数2 in イテラブル2]
これは次のfor文と互換になります。
リスト変数 = []
for 変数1 in イテラブル1:
    for 変数2 in イテラブル2:
        リスト変数.append(式)

2つのシーケンスの掛け合わせ

ary = [(x, y) for x in range(1, 4) for y in range(1, 3)]
print(ary)
Python リスト内包表記

以下と同じです。
ary = []
for x in range(1, 4):
    for y in range(1, 3):
        ary.append((x, y))
print(ary)
リストの中にはタプルを入れています。
(x, y)
これを
[x, y]
このようにすれば、リストの中にリストが入ります。

3重ループ

s = "VBA"
combi = [x+y+z for x in s for y in s for z in s if x != y != z != x]
print(combi)
Python リスト内包表記

"VBA"を3重ループで取り出し、
文字組み合わせのうち同じ文字が使われていないもののみリスト生成しています。
以下と同じです。
s = "VBA"
combi = []
for x in s:
    for y in s:
        for z in s:
            if x != y != z != x:
                combi.append(x+y+z)
print(combi)

リスト内包表記のネスト

公式ドキュメントでは、長さ4のリスト3つからなる3x4のmatrixの行と列を入れ替えています。
5.1.4. ネストしたリストの内包表記

これについては、この下と例と併せて読んでもらえれば分かると思います。
ただし、最後のzip()関数と引数リストのアンパックの部分が分かりづらいので、
この下のzip()関数とリスト内包表記の中で解説しています。

2次元配列作成→1次元配列に変換→2次元配列に変換
row, col = 5, 4
#2次元配列作成
ary2 = [[(r - 1) * col + c for c in range(1, col + 1)] for r in range(1, row + 1)]
print(ary2)
#1次元配列に変換
ary1 = [c for r in ary2 for c in r]
print(ary1)
#2次元配列に変換
ary2 = [ary1[i:i + col] for i in range(0, len(ary1), col)]
print(ary2)
Python リスト内包表記

上記の内包表記の2通りの多重for inを良く見比べてください。

[[式 for 変数2 in イテラブル2] for 変数1 in イテラブル1]
後ろに書いたループ1件ずつに対して、前半の内包表記が動きます。

[式 for 変数1 in イテラブル1 for 変数2 in イテラブル2]
左に書いたループ1件ずつに対して、後半の内包表記が動きます。

以下のfor文と見比べて動きを理解してください。
row, col = 5, 4
#2次元配列作成
ary2 = []
for r in range(1, row + 1):
    ary2.append([])
    for c in range(1, col + 1):
        ary2[r-1].append((r - 1) * col + c)
print(ary2)
#1次元配列に変換
ary1 = []
for r in ary2:
    for c in r:
        ary1.append(c)
print(ary1)
#2次元配列に変換
ary2 = []
for i in ary1:
    if i % col == 1:
        ary2.append(ary1[i-1:i-1+col])
print(ary2)

zip()関数とリスト内包表記

zip()関数

それぞれのイテラブルから要素を集めたイテレータを作ります。
公式ドキュメント - zip(*iterables)
zip(*iterables)

タプルのイテレータを返し、そのi番目のタプルは引数シーケンスまたはイテラブルそれぞれのi番目の要素を含みます。
このイテレータは、入力イテラブルの中で最短のものが尽きたときに止まります。
単一のイテラブル引数が与えられたときは、1要素のタプルからなるイテレータを返します。
引数がなければ、空のイテレータを返します。

2つの文字列から順番に取り出した2つの文字でリストを作成
s = "Python"
combi = [(s1, s2) for s1, s2 in zip(s, s[::-1])]
print(combi)
Python リスト内包表記

元の文字と、[::-1]これで反転した文字を先頭から1文字ずつ取り出してリストにしています。
以下と同じです。
combi = []
for s1, s2 in zip(s, s[::-1]):
    combi.append((s1, s2))
print(combi)

公式ドキュメントのネストしたリストの内包表記の後半部分の解説

公式ドキュメントでは、長さ4のリスト3つからなる3x4のmatrixの行と列を入れ替えています。
5.1.4. ネストしたリストの内包表記
以下は抜粋です。

Python リスト内包表記

実際には複雑な流れの式よりも組み込み関数を使う方が良いです。この場合 zip() 関数が良い仕事をしてくれるでしょう。

Python リスト内包表記

この行にあるアスタリスクの詳細については 引数リストのアンパック を参照してください。

zip()関数と引数リストのアンパックについて補足説明
matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
list(zip(*matrix))
まず、*matrix

Python リスト内包表記

*を付けたこれが引数リストのアンパックになります。
リストの要素1つずつが別々の引数(ここでは3つ)に展開されます。
そして、その3つの引数をzip()関数に渡しています。
つまり、
zip([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12])
このように指定したものと同じになります。
zip()関数は、3つのリストから要素をあつめます。
最初は、1,5,9、そして次は、2,6,10、・・・

Python リスト内包表記

enumerate()関数とリスト内包表記

enumerate()関数は以下で紹介しています。

第6回.for文とイテラブルオブジェクト - enumerate()関数

ここで紹介したスクリプトは、
for count, char in enumerate("Python"):
    print(str(count) + "番目の文字は"+char)
これをリスト内包表記にします。
[print(str(count) + "番目の文字は"+char) for count, char in enumerate("Python")]
これは良い例ではありません。
printせずに単純にリスト生成だけなら、分かり易いと思います。
[(count, char) for count, char in enumerate("Python")]
Python リスト内包表記


その他の内包表記

集合(set型)

リスト内包表記の[]を{}に変えると、集合(set型)の内包表記になります。
{i for i in range(1, 11)}
Python リスト内包表記

集合(set型)については、このPython入門ではデータ型の紹介では飛ばしています。
今後シリーズが進む過程の中で説明していく予定です。

公式ドキュメント - set(集合)型 --- set, frozenset
set オブジェクトは、固有の hashable オブジェクトの順序なしコレクションです。
通常の用途には、帰属テスト、シーケンスからの重複除去、積集合、和集合、差集合、対称差 (排他的論理和) のような数学的演算の計算が含まれます。

辞書(dict型)

リスト内包表記の[]を{}に変え、キートと値を指定すると辞書(dictt型)の内包表記になります。
{i: c for i, c in zip((1,2,3,4,5),"ABCDE")}
Python リスト内包表記




同じテーマ「Python入門」の記事

第14回.関数内関数(関数のネスト)とスコープ
第15回.lambda(ラムダ式、無名関数)と三項演算子
第16回.Pythonの引数は参照渡しだが・・・
第17回.リスト内包表記
第18回.例外処理(try文)とexception一覧
第19回.import文(パッケージ・モジュールのインポート)
第20回.フォルダとファイルの一覧を取得(os,glob,pathlib)
第21回.CSV読み込みとopen()関数とwith文
第22回.CSV読み書き(csvモジュール)
第23回.pipコマンド(外部ライブラリのインストール)
第24回.エクセルを操作する(openpyxl)


新着記事NEW ・・・新着記事一覧を見る

WEBスクレイピング(selenium)|Python入門(10月11日)
エクセルを操作する(pywin32:win32com)|Python入門(10月5日)
エクセルを操作する(openpyxl)|Python入門(10月3日)
pipコマンド(外部ライブラリのインストール)|Python入門(10月1日)
CSV読み書き(csvモジュール)|Python入門(9月29日)
「Excel 4.0 マクロ」の使い方|VBA技術解説(9月28日)
CSV読み込みとopen()関数とwith文|Python入門(9月28日)
フォルダとファイルの一覧を取得(os,glob,pathlib)|Python入門(9月26日)
import文(パッケージ・モジュールのインポート)|Python入門(9月24日)
例外処理(try文)とexception一覧|Python入門(9月23日)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.マクロって何?VBAって何?|VBA入門
6.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
7.繰り返し処理(For Next)|VBA入門
8.セルに文字を入れるとは(Range,Value)|VBA入門
9.とにかく書いてみよう(Sub,End Sub)|VBA入門
10.マクロはどこに書くの(VBEの起動)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ