0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

知っていて当たり前-11 その他の関数

Posted at

知っていて当たり前-11 その他の関数

1. 式の評価 eval()

文字列を式として評価(実行)する。

eval(Meta.parse("1 + 2"))
3

Meta.parse() は,Julia の抽象構文木(AST) を表す Expr 型のオブジェクトを返す。

Meta.parse("1 + 2")
:(1 + 2)
typeof(Meta.parse("1 + 2")), typeof(:(1 + 2))
(Expr, Expr)
eval(:(1 + 2)) # つまり eval(Meta.parse("1 + 2")) と同じ
3

文字列,Expr の中では $ による補間も使える。

a = 3
eval(Meta.parse("1 + $a"))
4
eval(:(1 + $a))
4

1.1. 関数を定義する例

func = "add"
eval(Meta.parse("$func(a, b) = a + b"))
add(10, 20) # 30
30

2. パイプ |>

多くの関数型のプログラム言語では,処理を行うために関数を入れ子で書くことが普通であった。

inv(sum(x -> x.^2, [1:5;]))
0.01818181818181818

データを「パイプ演算子 |>」 で次の関数の引数として渡すような書き方をすれば,処理の順番にプログラムを書くことができる。

[1:5;] |> x -> x.^2 |> sum |> inv
0.01818181818181818

適用する関数が複数の引数を保つ場合には,無名関数を使うことによって任意の位置の引数に渡すことができる。

using RDatasets, DataFrames
iris = dataset("datasets", "iris");
select(iris, :SepalLength) |> x -> first(x, 5)

5 rows × 1 columns

SepalLength
Float64
1 5.1
2 4.9
3 4.7
4 4.6
5 5.0

ベクトルをパイプで関数ベクトルにつなげると,要素に対応した関数が適用される。

["a", "list", "of", "strings"] .|> [uppercase, reverse, titlecase, length]
4-element Vector{Any}:
  "A"
  "tsil"
  "Of"
 7

3. 関数の合成

f(g(x)) は 関数 g に引数 x を与えた結果を関数 f の引数にすることである。

「合成演算子 」 を使って (f ∘ g)(x) と書くことができる。

sqrt(sum(1:10))
7.416198487095663
(sqrt  sum)(1:10)
7.416198487095663
1:10 |> sum |> sqrt
7.416198487095663
map(first  reverse  uppercase, split("you can compose functions like this"))
6-element Vector{Char}:
 'U': ASCII/Unicode U+0055 (category Lu: Letter, uppercase)
 'N': ASCII/Unicode U+004E (category Lu: Letter, uppercase)
 'E': ASCII/Unicode U+0045 (category Lu: Letter, uppercase)
 'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)
 'E': ASCII/Unicode U+0045 (category Lu: Letter, uppercase)
 'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)

4. リスト内包表記

リスト内包表記は Python での用語で,Julia ではリスト内包表記というのは変だと思う。Julia では ["123", "45", "6789"] はリストではないから。

Julia では,これを使う意味はない(使ってはならない)。for ループで書けば 10万倍速い(後述)。

[parse(Int, i) for i in ["123", "45", "6789"]]
3-element Vector{Int64}:
  123
   45
 6789

4.1. enumerate() を使う場合

enumerate(x) は 添字(インデックス)とベクトルの要素を同時に使用する。

[println("$i, $j") for (i, j) in enumerate(["123", "45", "6789"])]
1, 123
2, 45
3, 6789





3-element Vector{Nothing}:
 nothing
 nothing
 nothing

4.2. zip() を使う場合

zip(a, b, ...) はそれぞれのベクトルの要素を同時に使用する。

[println("$i, $j") for (i, j) in zip(["123", "45", "6789"], ["a", "b", "c"])]
123, a
45, b
6789, c





3-element Vector{Nothing}:
 nothing
 nothing
 nothing
@time x = [sqrt(i) for i in 1:100000000];
  0.237202 seconds (47.67 k allocations: 765.485 MiB, 2.92% gc time, 6.48% compilation time)
@time for i in 1:100000000
    sqrt(i)
end
  0.000001 seconds

4.3. 後置 if を使う場合

後半に if ... がある場合には,foo in bar 中の fooif の条件を満たすものに対してのみ処理が行われる。

[i^2 for i in 1:10 if i % 2 == 0]
5-element Vector{Int64}:
   4
  16
  36
  64
 100

4.4. 二重の内包表記

for を 1 回書くのと,2 回書くのでは違いがでてくる。

[10a + b for a=1:3, b=8:9]
3×2 Matrix{Int64}:
 18  19
 28  29
 38  39
[10a + b for a=1:3 for b=8:9]
6-element Vector{Int64}:
 18
 19
 28
 29
 38
 39

5. 辞書内包表記 Dict()

応用すべき例が思いつかない。

a = Dict(k for k = zip(["jp","USA","UK"], [0,1,2]))
Dict{String, Int64} with 3 entries:
  "USA" => 1
  "UK"  => 2
  "jp"  => 0
0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?