Python 無料で独習 029 Pythonの内包表記とは?

Python
この記事は約6分で読めます。

内包表記とは?

今回の講義はPythonの内包表記についてです。
内包表記・・・・
まったく初めて聞く単語です。
今日はしょっぱなから難しそうです(笑)

for文を用いて何か新しいリストを作成したい
そんなシチュエーションを思い浮かべてください。

例えばリストの中身を全て数値から文字列に変換したい場合です。
for文でリストの要素一つ一つ取り出し、
その要素を文字列に変換した上で
新しいリストに追加するという流れになるかと思います。

以上の流れをたったの一行で実装できるのが
内包表記らしいです。

なんだかすごい事ができそうですが、とにかく難しそうです。
とにかくコードを実際に書きながら学んでいきたいと思います。

内包表記リストに何かしらの値を追加していく際、一行で実装できる構文構造

内包表記 例1

import random

#1~100までの数値でランダムに出力します。
random.randint(1,100)

まず、ランダムに数字を発生させる
randomをインポート。
使い方としては
random.randint(1,100)で乱数を発生させる事を確認します。

data = []
for _ in range(1000):
  x = random.randint(1,100)
  data.append(x)

空のリストdata = []を定義。
x = random.randint(1,100)で1~100の間で乱数を発生させxに代入
data.append(x) dataにxの値を追加。
for _ in range(1000):でその処理を1000回繰り返してリストを作成

len(data)
1000

ちゃんと1000個のデータができているかlen()で確認。

data_10x = []

for datum in data:
  data_10x.append(datum*10)

data_10x[:10]
[430, 810, 260, 620, 970, 550, 680, 490, 120, 210]

先ほどつくったリストdataをもとに
data_10x = []
for datum in data:
  data_10x.append(datum*10)
dataを順番にdatumに代入して、
datumを10倍した値をdata_10xにリストとして追加していきます。

リストの中身の確認のために
data_10x[:10]
[430, 810, 260, 620, 970, 550, 680, 490, 120, 210]
0~10までのリストを表記させます。
ちゃんとできています。

このランダムに発生した数値で1000個のデータが入ったリストを作成
さらに、そのリストに10を掛けた値で新たなリストを作るというコード
を内包表記では下記となります。

new_data_10x = [datum*10 for datum in data]
new_data_10x[:10]
[430, 810, 260, 620, 970, 550, 680, 490, 120, 210]

みごとに新しく作ったリストnew_data_10xも同じ結果になっています。
これが内包表記というそうです。

new_data_10x = [datum*10 for datum in data]
と書くとあまり見慣れない書式なので正直戸惑います。
ただ今西先生いわく、慣れるととても便利だそうです。
利点としては、あたりまえですが
1行表記で見やすい。さらに処理速度も速いそうです。

%%timeit :と記述すると処理速度を測定できるそうです。
実際に測ると
普通のfor 文 86.7 µs
内包表記文 49.2 µs
で内包表記のほうがずいぶんと早いのがわかりました。

内包表記 例2 if文を用いた場合

data_odd = []
for datum in data:
  if datum % 2 != 0:
     data_odd.append(datum)

data_odd[:10]
[43, 81, 97, 55, 49, 21, 5, 19, 65, 39]

今回の例ではif文をつかいますので、
if datum % 2 != 0:
dataからdatumに値をいれて2で割って、余りが0ではない値のみを
リストdata_oddに入れていきます。
そのデータの10番目までの数字を表記させます。

これをまた内包表記で記述します。

new_data_odd = [datum for datum in data if datum % 2 != 0]
new_data_odd[:10]
[43, 81, 97, 55, 49, 21, 5, 19, 65, 39]

見事にfor文と同じ結果を出力することができました。
前回の
new_data_10x = [datum*10 for datum in data]
は10倍するという処理はforの前に記述しましたが、
new_data_odd = [datum for datum in data if datum % 2 != 0]
if文は後ろにくるみたいです。

内包表記 例3 if else を用いた場合

条件
50>=x (50以上の整数) → そのまま表示
50<x    (50未満の整数)   →     100倍
この条件でfor文で記述します。

data_50 = []
for datum in data:
  if datum >=50:
    data_50.append(datum)
  else:
    data_50.append(datum*100)

data_50[:10]
[4300, 81, 2600, 62, 97, 55, 68, 4900, 1200, 2100]

これを内包表記で記述すると下記となります。

new_data_50 = [datum if datum >=50 else datum*100 for datum in data]
new_data_50[:10]
[4300, 81, 2600, 62, 97, 55, 68, 4900, 1200, 2100]

ちゃんと同じ結果が得られました。
new_data_50 = [datum if datum >=50 else datum*100 for datum in data]
ifだけのときと違い、elseが入るとfor文の前に記述するそうです。

FizzBuzz問題

1から50までの数字を出力するプログラムを書いてください。
ただし、数字の3の倍数のときは数字の代わりにFizzと出力
5の倍数のときは数字の代わりにBuzzと出力してください。
3と5の倍数のときはFizz Buzzを出力。

初めにfor文で書きます

fizz_buzz = []

for i in range(1,51):
  if i%15==0:
    fizz_buzz.append('FizzBuzz')
  elif i%3==0:
    fizz_buzz.append('Fizz')
  elif i%5==0:
    fizz_buzz.append('Buzz')
  else:
    fizz_buzz.append(i)

これを内包表記で書きます。

new_fizz_buzz = ['FizzBuzz' if i%15==0 else 'Fizz' if i%3==0 else 'Buzz' if i%5==0 else i for i in range(1,51) ]

内包表記だと、if   else  などの並べ方をある程度覚える必要がありそうです。
ここまで横に長いとfor文で書いた方が簡単なような気が、、、
ただ、脱初学者とあったので上級になればなるほど、
こういったコードの書き方に慣れていかないといけないんでしょうね~
いや~難しかった~
今西先生、今日も有難うございました。

コメント

タイトルとURLをコピーしました