個人向,只會記錄一些需要注意的點。
前言
學習 Julia 已經有一段時間了,但是進步緩慢。這一方面是最近代碼寫得少,一方面是 Julia 學習資料少、中文資料更少,但也有我沒做筆記的緣故導致學習效率不佳。
最近發現一份很不錯的入門教程:Introducing_Julia,但是它的中文版本仍然有很多不足,就打算給它添加翻譯和潤色(zxj5470 完成了絕大部分翻譯工作),順便總結一份自己的筆記。
NOTE:Julia 的主要語言特征在於類型系統和多重派發,而主要的科學計算特征則是矩陣和整個標准庫及生態圈。
一、數組
在 Julia 中,數組被用作列表(lists)、向量(vectors)、表(tables)和矩陣(matrices)。
1. 數組的創建
這里尤其需要注意的是數組構造的幾種方法,以及它們的區別。
1.1 一維數組(vector/list)
julia> v = [1, 2, 3, 4] # 逗號分隔的語法用於創建一維數組
4-element Array{Int64,1}:
1
2
3
4
向量,指列向量,Julia 使用的是 Fortran Order,各種操作都是列優先於行的。(和 numpy 相反,numpy 是 C Order 的,行優先於列)
1.2. 二維數組(table/matrix)
julia> mat = [1 2 3 4] # 空格分隔的語法,用於創建二維數組(或稱行向量)
1×4 Array{Int64,2}:
1 2 3 4
julia> [1 2; 3 4] # 分號和換行符(\n),用於分隔數組中不同的行
2×2 Array{Int64,2}:
1 2
3 4
空格對應函數 hcat
,表示橫向拼接各個矩陣/元素。
分號和換行對應函數 vcat
,表示垂直拼接各個矩陣/元素。
下面的例子演示了拼接(空格)和單純分隔各個元素(逗號)的區別:
julia> [1 2 [3 4] 5] # 用空格做橫向拼接(或稱水平拼接)
1×5 Array{Int64,2}:
1 2 3 4 5
julia> [1, 2, [3, 4], 5] # 用逗號分隔
4-element Array{Any,1}:
1
2
[3, 4]
5
能看到在拼接操作中,[3 4]
被“解開”了,而用逗號時,它的行為和 Python 的 list
一樣(區別只是 Julia 的 list 列優先)。
使用拼接需要注意的情況舉例:
julia> [1 2 [3, 4] 5] # 橫向拼接要求 items 的行數相同!
ERROR: DimensionMismatch("mismatch in dimension 1 (expected 1 got 2)")
因為 [3, 4]
有兩行,而 數組中的其他項是數值,顯然行數不同,所以拋出了 Error.
可以想見,垂直拼接則要求 items 的列數相同。
另外當垂直拼接用於基本元素時,效果等同於逗號。(結果都是單列數組)
julia> v = [1, 2, 3, 4]
4-element Array{Int64,1}:
1
2
3
4
julia> h = [1; 2; 3; 4]
4-element Array{Int64,1}:
1
2
3
4
julia> [[1; 2]; [3, 4]] # 等價於 [[1, 2]; [3, 4]]
4-element Array{Int64,1}:
1
2
3
4
2. 數組的索引
數組的索引方式和 numpy 很類似。有很多高級索引方式。
這里我想說的是類似“齊次坐標”的索引特性。
首先,單個元素可以看作是零維的向量,數學上零維也可以看作是任意維,因此可以這樣玩:
julia> 2[1]
2
julia> 2[1, 1] # 被當成二維
2
julia> 2[1][1] # 2[1] 仍然是整數 2
2
julia> 2[1, 1, 1] # 三維
2
julia> 3.14[1]
3.14
julia> π[1, 1]
π = 3.1415926535897...
julia> '1'[1]
'1': ASCII/Unicode U+0031 (category Nd: Number, decimal digit)
julia> '1'[1, 1]
'1': ASCII/Unicode U+0031 (category Nd: Number, decimal digit)
多維數組也能使用類似“齊次坐標”的索引方式:
julia> m = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> m[1][1] # m[1] 是整數 1,這相當於 1[1]
1
julia> m[1, 1, 1]
1
julia> m[1, 1, 1, 1]
1
多維矩陣,在更高的維度上,也能被當成“零維”來看待,前面說過了“零維”也相當於“無限維”,所以多維數組也能用這么索引。
但是拓展的維度索引只能是 1!既然被看作“零維”,就只相當於一個點,自然不可能有更高的索引:
julia> 1[1, 2]
ERROR: BoundsError
julia> m[1, 1, 2]
ERROR: BoundsError: attempt to access 2×2 Array{Int64,2} at index [1, 1, 2]
...
julia> m[1, 1, 1, 2]
ERROR: BoundsError: attempt to access 2×2 Array{Int64,2} at index [1, 1, 1, 2]
...
3. 推導式(comprehension)與生成器表達式(generator expression)
和 Python 的列表推導式與生成器表達式很像,但是更強大——Julia 是面向矩陣的。
julia> [i+j for i in 1:3 for j in 1:3] # 這個語法和 Python 一致
9-element Array{Int64,1}:
2
3
4
3
4
5
4
5
6
julia> [i+j for i in 1:3, j in 1:3] # 這個是多維的語法
3×3 Array{Int64,2}:
2 3 4
3 4 5
4 5 6
julia> [i+j for i in 1:3, j in 1:3 if iseven(i+j)] # 在后面加 guard 的情況下,結果坍縮成一維(這時兩種語法結果沒有差別)
5-element Array{Int64,1}:
2
4
4
4
6
julia> [(iseven(i+j) ? 1 : 2) for i in 1:3, j in 1:3] # 在前面做判斷,因為沒有過濾元素,所以仍然保持了原有結構。
3×3 Array{Int64,2}:
1 2 1
2 1 2
1 2 1