はじめに
仕事で Python を使っていて、
「あー、ここのリスト作る処理、リスト内包表記にしたら簡潔に書けるのになー。」
と思うことがあります。
でも、私がリスト内包表記を書きたいと思う場面が意外と少ないため、いざ書こうと思ったときに、
「あれ、リスト内包表記って、どうやって書くんだっけ?うーん、時間もないし、いつも通りループにするか。」
と、残念な感じになるので、私自身のための覚え書きの意味も含めて。
#リスト内包表記とは?
初めてこの言葉を聞いたときは、頭の中が?マークだらけに。。。
すごーく簡単に言うと、リスト内包表記とは、
リストデータを1行で作る方法
です。
ただし、何でも1行で書けるわけではなく、(若干語弊がありますが、)ループでリストを作成する処理を1行で書けるものです。
私自身、「仕事で書くコードは複雑なんだよ!」と思っていたのですが、意外と使えます。
#書き方
##通常のループ(これはリスト内包表記ではありません。)
data = []
for i in range(10):
data.append(i)
print(data)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
##リスト内包表記
print([i for i in range(10)])
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
###解説
通常のループと、リスト内包表記の結果は同じです。
しかし、リスト内包表記の方が、記述量が少なくてすみます。
そして、コードが簡潔で読みやすくなります。(慣れないと読みにくいですが。)
リスト内包表記のコードを見ていきます。
[...]
ご存知の通り、これでリストができるため、通常のループの data = []
が不要になります。
for i in range(10)
これは通常のループでも、リスト内包表記でも同じです。
ただし、リスト内包表記の方には、 :
は不要です。
i for i in range(10)
最初にでてくる i
は、ループで取り出した i
(2つめの i
)の値が格納されます。
ループのたびに最初にでてくる i
の値が書き換わります。
その i
が、ループの回数分、リストに追記(append)されます。
#もう少し具体的に
もう少し具体的な方が理解しやすいと思うので、次のケースで説明します。
##ケース1
リスト内のデータを加工したい場合。
例えば、 ['aa', 'b', 'ccc']
というリストの各データに、 @
を付加したい場合。
items = ['aa', 'b', 'ccc']
print([item + '@' for item in items])
# ['aa@', 'b@', 'ccc@']
items
のデータに @
をつけて、別のリストを作成しています。
リストデータから、別のリストデータを1行で作ったというわけです。
##ケース2
データ加工処理など、決まったルールで文字列の途中に、別の文字を付加したい場合。
例えば、abcdefgh
というデータに1文字ごとに、 -
を付加したい場合。
items = 'abcdefgh'
print('-'.join([item for item in items]))
# a-b-c-d-e-f-g-h
こちらは、文字列からリストデータを1行で作っています。
そのリストのデータを -
で join
して文字列に戻しています。
[追記]
コメントをいただいたので、追記します。
リスト内包表記を使わなくても実現できました。無駄がなくていいです。
items = 'abcdefgh'
print('-'.join(items))
# a-b-c-d-e-f-g-h
ちなみに、2文字ごとに、 -
を付加したい場合。
items = 'abcdefgh'
print('-'.join([items[i*2: i*2+2] for i in range(int(len(items)/2))]))
# ab-cd-ef-gh
ちょっと詰め込みすぎな感じがするので、こんな感じでしょうか。
items = 'abcdefgh'
loop_count = int(len(items)/2)
print('-'.join([items[i*2: i*2+2] for i in range(loop_count)]))
# ab-cd-ef-gh
[追記]
こちらもコメントをいただいたので、追記します。
上の場合は、i
というカウンタを使うため、範囲外アクセスが起こる可能性があります。
それを回避した書き方です。
items = 'abcdefgh'
print('-'.join(ch1+ch2 for ch1, ch2 in zip(items[::2], items[1::2])))
# ab-cd-ef-gh
カウンタを使う場合、使わない場合でも、文字が奇数個の場合、最後の1文字が出力されないことがわかりました。
カウンタを使うことになりますが、回避できました。
import math
items = 'abcdefghi'
loop_count = math.ceil(len(items) / 2)
print('-'.join([items[i*2: i*2+2] for i in range(loop_count)]))
# ab-cd-ef-gh-i
#最後に
ケース1では、リストのデータを加工して、別のリストを作る、
ケース2では、文字列を加工して、リストを作る、というサンプルです。
どちらのケースも、ループを使って実現できますが、
リスト内包表記を使えば、シンプルかつ簡潔にコードが書けます。