#内包表記はいいぞ
Pythonは内包表記という書き方ができます.スライスと同じくらい便利なので,これも覚えておきたいです.
そもそも内包って?
「内包」とは集合論における「内包的記法」に由来します.
高校時代の数学Aなどで習ったと思いますが,集合の表し方には2種類あり,
- 外延的記法
- 内包的記法
があります.
外延的記法は単に集合に属する要素を直接書き下す記法で,
例えば{1,3,5,7,9}のように書きます.
内包的記法はまず集合に属する要素xを宣言したのち,xが満たすべき条件を示します.
例えば{x | xは10以下の奇数}ですね.
基本的な内包表記
これをPythonで書くとこのようになります.
s = {x for x in range(10) if x % 2 == 1}
print(s) #{1,3,5,7,9}
Pythonの内包表記における基本構文はx for x in 何か
で,後ろにif文などを持ってくることで条件を指定します.
今回はset,つまりpythonにおける集合に対して内包表記を適用しましたが,もちろん{}を[]に変えるだけでリストでも可能です.
別解
ちなみに、今回は説明の都合上無理矢理内包表記を使いましたが、別に第3回 スライス編で扱ったrangeで書いた方が簡潔です。
print([*range(1,10,2)]) #[1, 3, 5, 7, 9]
辞書内包表記
辞書型(dict, defaultdictなど)でも内包表記が可能です.
from collections import defaultdict
key_list = ['a','bb','ccc','dddd','eeeee']
value_list = [1,2,3,4,5]
#辞書作成
dd = defaultdict(int, zip(key_list, value_list))
#ddにあるもののうち,valueが偶数のものだけ抽出して新たに辞書を作成
dd2 = {key:dd[key] for key in dd if dd[key]%2==0}
print(dd2) #{'dddd': 4, 'bb': 2}
#ddにあるもののうち,keyの長さが3以上のものだけ抽出して新たに辞書を作成
dd3 = {key:dd[key] for key in dd if len(key) >= 3}
print(dd3) #{'ccc': 3, 'dddd': 4, 'eeeee': 5}
elseを入れる(三項演算子)
if付きの内包表記にelseを付けることもできます.
しかしelseを付けると三項演算子扱いになるので似て非なるものになります.
#1~40の数字のうち3の倍数と3のつく数字の時だけ処理を変える
fool = [str(i) + '~~!!' if i % 3 == 0 or '3' in str(i) else i for i in range(1,41)]
print(fool)
#[1, 2, '3~~!!', 4, 5, '6~~!!', ... 29, '30~~!!', '31~~!!', '32~~!!', '33~~!!', ... 40]
当然30からの勢いが物凄いことになりますね.
それはさておき,if付き内包表記にelseが付くと最初に三項演算子(処理1 if 処理1を行う条件 else 処理2
)の記述を行った後にforが来ます.if~elseをforの後ろに付けても動きません.紛らわしいですが気を付けましょう.
二重内包表記
要はforの部分を二重にできるということです.
以下は二次元配列を一次元配列にする内包表記です.
listA = [[1,2], [3,4], [5,6]]
flat = [flatten for inner in listA for flatten in inner]
print(flatten) #[1,2,3,4,5,6]
初見だと随分見にくいですね.
まず最初のflattenで大きく切れて,そこから二重for文が続いているイメージです.
flat = [
flatten
for inner in listA
for flatten in inner
]
#さいごに
内包表記は確かに簡潔に書けますが,精々これぐらいの複雑さにとどめておかないと可読性が失われます.
用法容量を守って正しく使いましょう.