リスト内包表記について

これを使えるかどうかでPython熟練度がなんとなくバレてしまうっていうリスト内包表記、英語で言うとList Comprehension。シンタックスとしては

 

[ expression for item in iterable ]  

という単純なものなんだけど、これがどんどん複雑になってくると僕は訳がわからなくなってくる。まずは単純な例から・・・

one_to_five = []

for num in range(1, 6):

    one_to_five.append(num)

 

print(one_to_five)

>>> [1, 2, 3, 4, 5]

↑をリスト内包表記で表現すると

one_to_five = [ num for num in range(1, 6) ]

print(one_to_five)

[1, 2, 3, 4, 5]

ここまではなんとなくわかる。次にシンタックスの最初にある"expression"を色々いじってみる。

new_list = [ num**2 for num in range(1, 6) ]

>> [1, 4, 9, 16]

なんかイメージとしては、最初にexpression以外の所を書いて、そんで最後にそのnumなり何なりに「何をしたいか」を打つのが言葉の順番的にはわかりやすい。。

ifコンディションを入れる

なんかexcelでこうゆう操作するなーって思い出したんだけど、シンタックスとしては以下

[ expresssion for item in iterable if condition ]

今はなき世界のナベアツのネタで、「3の倍数だけ馬鹿になります」っていうのがあるんだけど、とりあえず3の倍数だけ抽出してみる。

san_baka = [str(num)+'!!!' for num in range(1, 41) if num%3 == 0]

print(san_baka)

>>> ['3!!!', '6!!!', '9!!!', '12!!!', '15!!!', '18!!!', '21!!!', '24!!!', '27!!!', '30!!!', '33!!!', '36!!!', '39!!!']

まずはOK。でも本当は「3の倍数と、3のつく数字だけ馬鹿になります」っていうネタなので、更に修正。 python

san_baka = [str(num)+'!!!' for num in range(1, 41) if num%3 == 0 or '3' in str(num)]

print(san_baka)

>>>['3!!!', '6!!!', '9!!!', '12!!!', '13!!!', '15!!!', '18!!!', '21!!!', '23!!!', '24!!!', '27!!!', '30!!!', '31!!!', '32!!!', '33!!!', '34!!!', '35!!!', '36!!!', '37!!!', '38!!!', '39!!!']

OKOK。31くらいで爆笑が取れるはず。 でもまだ完璧じゃなくて、「3の倍数と3がつく数字」以外はシュールに読み上げなくてはいけない。つまり"!!!"を付けたくない訳なので、更に修正する。

--- ここで10分googleで調べまくった ---

どうやらelseを付ける場合は文法が若干変わるっぽい。

san_baka = [str(num)+'!!!' 
if num%3 == 0 or '3' in str(num) else num for num in range(1, 41)]

print(san_baka)

>>> [1, 2, '3!!!', 4, 5, '6!!!', 7, 8, '9!!!', 10, 11, '12!!!', '13!!!', 14, '15!!!', 16, 17, '18!!!', 19, 20, '21!!!', 22, '23!!!', '24!!!', 25, 26, '27!!!', 28, 29, '30!!!', '31!!!', '32!!!', '33!!!', '34!!!', '35!!!', '36!!!', '37!!!', '38!!!', '39!!!', 40]

参考にしたstack overflowのスレッド

stackoverflow.com

よしよし。これで最後の「40」を真顔に戻ってシュールに言う事で、第二の爆笑が取れるはずだ。ちなみにちょっと前に新宿のルミネ吉本行ったら落語家になったナベアツが出てたんだけど、個人的にはまったく面白くなかった。ごめんなさい。

リスト内包表記の中でfor文を回す

ネストされたループってあるじゃんか

rows = [1, 2, 3, 4]
cols = ['a', 'b', 'c', 'd']

for row in rows:
    for col in cols:
        print(row, col)

>>> 1 a
1 b
1 c
1 d
2 a
2 b
2 c
2 d
3 a
3 b
3 c
3 d
4 a
4 b
4 c
4 d

これを包括表記で打つと

cells = [(row, col) for row in rows for col in cols]
print(cells)

>>>[(1, 'a'), (1, 'b'), (1, 'c'), (1, 'd'), (2, 'a'), (2, 'b'), (2, 'c'), (2, 'd'), (3, 'a'), (3, 'b'), (3, 'c'), (3, 'd'), (4, 'a'), (4, 'b'), (4, 'c'), (4, 'd')]

こうなる。forが一行に2回出てくるとか、逆に読みにくいんじゃ・・・とも思う訳だけれど、きっと内部速度的には早くなっているのだろう。ただこれ、tupleの形になので、一応見た目だけそれっぽくするならexpressionの箇所を変えれば良い。

cells = ["{} {}".format(row, col) for row in rows for col in cols]
print(cells)

>>>  ['1 a', '1 b', '1 c', '1 d', '2 a', '2 b', '2 c', '2 d', '3 a', '3 b', '3 c', '3 d', '4 a', '4 b', '4 c', '4 d']

 じゃーここまでの知識で何かやってみよう

友愛数を見つけてそれをリスト化する」っていうのを内包表記内でやろうと思う。これ言ってる時点で思っているのが、「糞長い一行になりそう・・・」って事。あとさすがのmacbook先生でも、計算に時間がかかりそう・・・って事。

友愛数とは! 異なる2つの自然数の組で、自身を除いた約数の和が、互いに等しくなる数。ちなみに最小の友愛数は220と284。