Help us understand the problem. What is going on with this article?

Pythonのリスト内包表記でいつも混乱するので覚え書き

はじめに

仕事で 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では、文字列を加工して、リストを作る、というサンプルです。

どちらのケースも、ループを使って実現できますが、
リスト内包表記を使えば、シンプルかつ簡潔にコードが書けます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした