Edited at

[Python] 内包表記Tips

More than 1 year has passed since last update.


はじめに

Pythonで自分がよく使う内包表記のスニペットです。

毎回のように「あれやりたいんだけど、どう書くんだっけ?」と思って考え直したりしてるので、まとめておきます。

今後も継続的に追加していく予定。

中には、内包表記で書くよりも簡単なライブラリが存在するものもあると思います。

個人的に、ライブラリ使うまでもないものは使わない派。


Tips


dict から dict(Key-Value形式)のlist に。


# 入力値
dict_A = {
"A": "aaaaa",
"B": "bbbbb",
}

# 得たい結果
result = [
{"Key": "A", "Value": "aaaaa"},
{"Key": "B", "Value": "bbbbb"},
]

# スニペット
result = [ { "Key":k, "Value":v } for k,v in dict_A.items() ]


dict(Key-Value形式)のlist から 1つのdict に。


# 入力値
list_A = [
{"Key": "A", "Value": "aaaaa"},
{"Key": "B", "Value": "bbbbb"},
]

# 得たい結果
result = {
"A": "aaaaa",
"B": "bbbbb",
}

# スニペット
result = {x["Key"]:x["Value"] for x in list_A}


dictから特定キーのみ抜き出し


# 入力値
dict_A = {
"A": "aaa",
"B": "bbb",
"C": "ccc",
"D": "ddd",
}

target_keys = ["A", "C"]

# 得たい結果
result = {
"A": "aaa",
"C": "ccc",
}

# スニペット
result = { k:v for k,v in dict_A.items() if k in target_keys }


dictのlistから、特定キーのみ抜き出したlistに。

# 入力値

list_A = [
{
"A": "aaa",
"B": "bbb",
"C": "ccc",
"D": "ddd",
},
{
"A": 123,
"B": 456,
"C": 789,
},
{
"A": "あいう",
"C": "かきく",
"D": "さしす",
},
]

target_keys = ["A", "B"]

# 得たい結果
result = [
{
"A": "aaa",
"B": "bbb",
},
{
"A": 123,
"B": 456,
},
{
"A": "あいう",
},
]

# スニペット
result = [ { k:v for k,v in x.items() if k in target_keys } for x in list_A ]


dict をマージ

標準の dict.update() でも出来ますが、1行で済ませたい&元の変数を破壊したくない場合に。

# 入力値

dict_A = {
"A": "aaa",
"B": "bbb",
"C": "ccc",
}
dict_B = {
"D": 123,
"E": 345,
}
dict_C = {
"B": "らりる",
"E": "わをん",
}

# 得たい結果
result = {
"A": "aaa",
"B": "らりる",
"C": "ccc",
"D": 123,
"E": "わをん",
}

# スニペット
result = { k:v for x in [dict_A, dict_B, dict_C] for k,v in x.items() }

# 追記:内包表記を使うまでもなかった。キーワード展開で。
result = { **dict_A, **dict_B, **dict_C }


list(またはdict) の list の総件数を取得

# 入力値

list_A = [
["a", "b", "c", "d"],
["AA", "BB"],
{
"あいう": 123456,
"かきく": 234567,
"さしす": 456789,
}
]

# 得たい結果
result = 9 # 4 + 2 + 3

# スニペット
result = sum( [ len(x) for x in list_A ] )

# 追記:こういう書き方も。
result = sum( len(x) for x in list_A )

[ ]で括ってlist化するかはお好みで。

自分の環境ではlist化したほうが僅かに高速でした。

CPU・メモリ負荷は不明(未調査)。inputの内容やlistサイズ次第?


listのlistから、特定の値の件数を取得

# 入力値

list_A = [
["a", "b", "c", "a", "d", "a"],
["A", "B", "C", "D"],
["b", "x", "a", "y", "a"],
]

search_value = "a" # 件数を取得したい値

# 得たい結果
result = 5

# スニペット
result = len([ y for x in list_A for y in x if y == search_value ])

# 追記:こういう書き方も。
result = sum(1 for x in list_A for y in x if y == search_value)

# 追記:こういう書き方も。条件は完全一致に限るが最速。
result = sum(x.count(search_value) for x in list_A)

末尾の if y == search_value のところを変更すれば、完全一致だけでなく色々な条件で実行可能。


dictキーのCase(大文字/小文字)を揃える。

キー名のサンプルを与えて、大文字/小文字の区別なく同じものがあったらサンプルに合わせてキーを変換。

サンプルに無いものはそのまま。

重複するものがあったら、元のキー名でソートした結果でより後に出てくるものが勝つ。

# 入力値

key_sample = ["AAA", "BBB", "ZZZ"]
dict_A = {
"aaa" : "a1 ... 'aaa' to 'AAA'",
"bbB" : "b1 ... Loser of the latter win rule",
"bbb" : "b2 ... Winner of the latter win rule",
"BbB" : "b3 ... Loser of the latter win rule",
"ccc" : "c1 ... no change"
}

# 得たい結果
result = {
"BBB": "b2 ... Winner of the latter win rule",
"AAA": "a1 ... 'aaa' to 'AAA'",
"ccc": "c1 ... no change"
}

# スニペット
key_sample_lower = { x.lower():x for x in sorted(key_sample) }
result = { (key_sample_lower.get(k.lower(),k)):v for k,v in sorted(dict_A.items()) }


Case(大文字/小文字)を無視したDictキー重複チェック

Caseを無視した場合に同じキーが存在するものだけ、それぞれの件数を取得する。

# 入力値

dict_A = {
"aaa" : "a1",
"bbb" : "b1",
"ccc" : "c1",
"ddd" : "d1",
"aaA" : "a2",
"bbB" : "b2",
"bBB" : "b3",
}

# 得たい結果
result = {
"aaa": 2,
"bbb": 3
}

# スニペット
keys_lower = [ x.lower() for x in dict_A.keys() ]
result = { x.lower():keys_lower.count(x.lower())
for x in dict_A if keys_lower.count(x.lower()) > 1 }