LoginSignup
2
4

More than 5 years have passed since last update.

Pythonのリスト内包表記(forの順番)

Last updated at Posted at 2019-03-26

今日、Pythonをいじっているとリスト内包表記でハマったので、その経験をメモしておこうと思う。

問題

x = ['a', 'b', 'c']
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = [y for y in x for x in a]
print(b)

(意味ありげな1行目は置いておいて)この実行結果は、

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

となった。

僕は、

[1, 2, 3, 4, 5, 6, 7, 8, 9]

となることを期待していた。というのも、リスト内包表記ではforの順序は関係ないと思っていたので、リスト平坦化のイディオムである、

x = ['a', 'b', 'c']
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = [y for x in a for y in x]
print(b)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

からの類推でそうなるものだと思っていた。

理由

リスト内包表記は一種の糖皮構文で、それをforで書き下せばわかりやすくなる。

問題の、

b = [y for y in x for x in a]

は、

b = []
for y in x:
    for x in a:
        b += [y]

と同じことだ。

ここで、for y in xxは、この行が読み込まれた時の状態で固定されることに注意する。例えば、

x = [1, 2, 3]
for y in x:
    x = ['a', 'b', 'c']
    print(y)
# 1
# 2
# 3

となる。

これをもう少し分かり易く書けば、

for y in [1, 2, 3]:
    x = ['a', 'b', 'c']
    print(y)

という感じで実行されるので、for文内でxに別の値を代入しても、for文の実行には影響しない。

以上のことに注意して、

x = ['a', 'b', 'c']
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = [y for y in x for x in a]
print(b)

をfor文で書き直せば、

b = []
for y in ['a', 'b', 'c']:
    for x in [[1, 2, 3], [4, 5, 6], [7, 8, 9]]:
        b += [y]
print(b)

となる。これの実行結果が、

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

となることに疑問はないだろう。

リストの平坦化

二重リストを平坦化(一重リスト化)する方法として、

x = ['a', 'b', 'c']
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = [y for x in a for y in x]
print(b)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

を紹介したが、これもfor文で書き下して見る。

b = []
for x in [[1, 2, 3], [4, 5, 6], [7, 8, 9]]:
    for y in x:
        b += [y]
print(b)

となるので、二重リストを平坦化できるのである。

2
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4