kicks.jp blog

ベトナム関連のブログ

Pythonのリスト内包表記(その2)

前回に引き続いてPythonのリスト内包表記について書きます。
前回の記事を書くために試したコードを載せただけの記事です。
blog.kicks.jp

後半は、辞書内包表記(Dictionary Comprehension)になっている所もあります。

元になるリスト(その1)

list1 = ['a', 'b', 'c', 'd']

基本その1

元のリストと同じリストを生成。

result0 = [v for v in list1]
print(list1)

出力結果:

['a', 'b', 'c', 'd']

基本その2

要素の文字列を2文字にする。(元のリストと違ったリストにするため)

# 1. Make each element 2 chars
result1 = [v + v for v in list1]
print(result1)

出力結果:

['aa', 'bb', 'cc', 'dd']

条件(Condition)を付ける

'd'を除外する。

# 2. Exclude 'd'
result2 = [v + v for v in list1 if v is not 'd']
print(result2)

出力結果:

['aa', 'bb', 'cc']

リスト内包表記と同じ結果を得る

forループを使った場合
# 3. Use for-loop instead of list comprehension
result3 = []
for v in list1:
    v1 = v + v
    result3.append(v1)
print(result3)

出力結果:

['aa', 'bb', 'cc', 'dd']
map()関数とlambda式を使った場合
# 4. Use map() and lambda in loop
result1 = map(lambda val: val + val, list1)
result1 = list(result1)
print(result1)

出力結果:

['aa', 'bb', 'cc', 'dd']
map()関数とユーザー定義関数を使った場合
# 5. Use map() and user-defined-function
def concat1(val):
    return val + val

result5 = list(map(concat1, list1))
print(result5)

出力結果:

['aa', 'bb', 'cc', 'dd']

繰り返し回数を取得する

enumerate()で囲むと、forのあとの変数を2つ指定できて、index, valueになります。

# 6. Get index for list
result5 = [v1 + str(i) for i, v1 in enumerate(list1)]
print(result5)

出力結果:

['a0', 'b1', 'c2', 'd3']

元になるリスト(その2)

list2 = [
    {'id': 1, 'name': 'mike'},
    {'id': 2, 'name': 'susan'},
    {'id': 3, 'name': 'kubotti'},
]

前回の記事にも登場したリストです。
dict型の要素3つがリストになっています。

出力結果 :

[{'id': 1, 'name': 'mike'}, {'id': 2, 'name': 'susan'}, {'id': 3, 'name': 'kubotti'}]

条件(Condition)を付ける

# 1. Get only 1,2
result1 = [rec for rec in list2 if rec['id'] < 3]
print(result1)

出力結果:

[{'id': 1, 'name': 'mike'}, {'id': 2, 'name': 'susan'}]

2階層目の特定の要素だけのリストを作る

# 2. Create list of 'name'
result2 = [rec['name'] for rec in list2]
print(result2)

出力結果:

['mike', 'susan', 'kubotti']

dictのkey, valueを取得する

2階層目のdictを、value(値)だけのリストにする例です。

[val for key, val in rec.items()]

とするとdictのkeyとvalueを取得できます。valueしか使っていないので、valueのリストになります。

# 3. Transform to list
result3 = [[val for key, val in rec.items()] for rec in list2]
print(result3)

出力結果:

[[1, 'mike'], [2, 'susan'], [3, 'kubotti']]

dictの値を更新する

# 4. Add '_1' to name
result4 = [{'id': rec['id'], 'name1': rec['name'] + '_1'} for rec in list2]
print(result4)

出力結果:

[{'id': 1, 'name1': 'mike_1'}, {'id': 2, 'name1': 'susan_1'}, {'id': 3, 'name1': 'kubotti_1'}]

元のリストと同じリストを作る

# 5. Do nothing
result5 = [{key: val for key, val in rec.items()} for rec in list2]
print(result5)

出力結果:

[{'id': 1, 'name': 'mike'}, {'id': 2, 'name': 'susan'}, {'id': 3, 'name': 'kubotti'}]

dictの特定のキーで値を書き換える

'name'の値に'_1'をつけたかったのですが最初はうまくいきませんでした。

# not work
result6 = {'name':'test1' if False else 'name':'test2'}

上のコードは構文エラーになります。

以下のようにすると動いたのですが、なんでelseの後に指定できるのがvalueだけなんだろう・・?と思いました。

# 6. Add '_1' to 'name' value.
result6 = [{key: value if key != "name" else value + "_1" for key, value in rec.items()} for rec in list2]
print(result6)

出力結果:

[{'id': 1, 'name': 'mike_1'}, {'id': 2, 'name': 'susan_1'}, {'id': 3, 'name': 'kubotti_1'}]

調べた結果、dictを生成するときの条件は、keyとvalueそれぞれに対して書く(書ける)ということでした。
https://stackoverflow.com/questions/4260280/if-else-in-pythons-list-comprehension

# Works well
result6 = {'name': 'test1' if False else 'test2'}
print(result6)
# Left side 'if' statement is a conditional expression, right side 'if' is a comprehension syntax.
result6 = {'name': 'test1' if False else 'test2' for k in range(1) if True}
print(result6)

左側のif文は条件式(conditional expression)、右側のif文は、辞書内包表記の構文(comprehension syntax)です。

dictの条件式は、最初↓の形式かと思っていましたが、

# not work
result6 = {('name1': 'test1') if False else ('name2': 'test2')}
result6 = {('name1' if True else 'name2'): ('test1' if False else 'test2')}

が正しい構文でした。

特定のキーだったら値を書き換える

result7 = [{key: value if key != 'name' else value + '_1' for key, value in rec.items()} for rec in list2]
print(result7)

出力結果:

[{'id': 1, 'name': 'mike_1'}, {'id': 2, 'name': 'susan_1'}, {'id': 3, 'name': 'kubotti_1'}]

関数を使う方法:

def modify_rec(rec):
    record = {
        'id': rec['id'],
        'name': rec['name'] + '_1'
    }
    return record

# 7-1. Add '_1' using map() with user-defined-function
result7 = list(map(modify_rec, list2))
print(result7)

# 7-2. Add '_1' using list comprehension with user-defined-function
result7 = [modify_rec(rec) for rec in list2]
print(result7)

出力結果:

[{'id': 1, 'name': 'mike_1'}, {'id': 2, 'name': 'susan_1'}, {'id': 3, 'name': 'kubotti_1'}]

要素の追加

リスト内包表記ではないですが、listに要素を追加。

dict1 = {'id': 4, 'name': 'taro'}
list2.append(dict1)
print(list2)

出力結果:

[{'id': 1, 'name': 'mike'}, {'id': 2, 'name': 'susan'}, {'id': 3, 'name': 'kubotti'}, {'id': 4, 'name': 'taro'}]

dict型がリストになったデータのdictに値を追加

[rec.update({'number': str(i+1).zfill(4)}) for i, rec in enumerate(list2)]
print(list2)

出力結果:

[{'id': 1, 'name': 'mike', 'number': '0001'}, {'id': 2, 'name': 'susan', 'number': '0002'}, {'id': 3, 'name': 'kubotti', 'number': '0003'}, {'id': 4, 'name': 'taro', 'number': '0004'}]

まとめ

記事の後半はリスト内包表記と関係ない構文になってきたような・・?
役に立ちそうな例を見つけたら追記します。