はじめに
今日は内包表記について書いていきます。
2019/05/13 追記:内包表記がforループより遅くなってしまったと書きましたが、
実行速度が遅くなってしまった原因はグローバルで実行したためでした。
リスト内包表記
内包表記の基本構文は以下の通りです。
[変数 for 変数 in イタレーター]
num = [n for n = 1:5]
> [1, 2, 3, 4, 5]
後置if文を置くことで、イタレーターで取り出す変数に条件をつけることができます。
a = [num for num in 1:10 if num % 2 == 0]
> [2, 4, 6, 8, 10]
前置if文も記載することで、リストに入れる値に分岐つけて処理をすることができます。
前置if文は複合式として書きます。
# 奇数は二乗します
a = [(if num % 2 == 0 num else num^2 end) for num in 1:10]
> [1, 2, 9, 4, 25, 6, 49, 8, 81, 10]
辞書内包表記
辞書内包表記はzip関数を使用します。
a = Dict(k for k = zip(["jp","USA","UK"], [0,1,2]))
> ( "USA" => 1, "UK" => 2, "jp" => 0)
zip関数はそれぞれの要素のタプルが返ってきます。
それぞれの要素をアンパッキングする場合は、下記のようにタプルで指定しないとエラーになります。
a = Dict((k,v) for (k,v) = zip(["jp","USA","UK"], [0,1,2]))
> ( "USA" => 1, "UK" => 2, "jp" => 0)
#これはエラーになります。↓
a = Dict((k,v) for k,v = zip(["jp","USA","UK"], [0,1,2]))
syntax: invalid iteration specification
それぞれの要素をアンパッキングすれば、下記のように条件を指定することができます。
a = Dict((k,v) for (k,v) = zip(["jp","USA","UK"], [0,1,2]) if v % 2 == 0)
> ("UK" => 2, "jp" => 0)
速度について
Pythonではforループでリストを作るより、リスト内包表記で作る方が速いです。
Juliaではどうか、検証してみました。
- リスト内包表記
2019/05/13 追記: このベンチマークは正しい比較になっていないので、下記の追記を参照してください!
@time [num for num in 1:5 ]
> 0.026119 seconds (53.28 k allocations: 2.622 MiB)
- for loop
@time begin
begin
b = []
for num2 in 1:5
push!(b,num2)
end
b
end
end
> 0.000005 seconds (3 allocations: 208 bytes)
予想以上にforループがあまりにも早くて、びっくりです。
一応、確認のために複合式でも計測してみました、
@time (c = []; for num2 in 1:5 push!(c,num2) end; c)
> 0.000009 seconds (3 allocations: 208 bytes)
あまり、速度に変化がないので正しく計測できていることにします。
Juliaのforループは非常に高速なので、速度を気にしてリスト内包表記にする必要ないみたいです。
2019/05/13 追記
コメントでご指摘を受けまして、再度速度検証しました。
内包表記が速度が遅い原因は、グローバルで実行しているためです。
Juliaのドキュメントにも、グローバルは避けましょうと書いてあるのに、
グローバルでベンチマークとったことを反省・・・
適当に関数でラップすると爆速になりました。
f() = [num for num in 1:5 ]
@time f()
0.000002 seconds (5 allocations: 288 bytes)
5-element Array{Int64,1}:
1
2
3
4
5
また、コメントでもご指摘のBenchmarkToolsを使うのが、ベンチマークの正しい取り方だと思います。
↑ドキュメントにもきちんとそう書いてあるorz
まとめ
Juliaの内包表記は簡単に記載できます。
しかし、速度面ではあまりメリットはありませんが、
リストの初期化処理などをシンプルに記載できるかと思います。
2019/05/13 追記 Juliaでも内包表記爆速です。
Juliaではグローバルで実行したり、変数作ったりするとかなり実行速度が落ちることがわかりました。