許多程式語言都有類似 null 或 none 的方式,用來表示不存在的值。
由於 Julia 的設計目標是處理大量(而且往往雜亂)的資料,因此它擁有多種表示「空無」的形式。
整體目標是在遇到缺失或可疑的值時加以標記,然後繼續執行,而不引發例外。
nothing如果某個值真的不存在,就會用 nothing 來表示。這大概最接近 C(NULL)或 Python(None)的做法。
julia> n = nothing
julia> isnothing(n)
true
julia> typeof(n)
Nothing
所以 nothing 是型別 Nothing 的單例值,我們可以對它進行測試。
nothing 的一個常見用途,是當作只為了副作用(例如列印、網路設定等)而使用的函式的回傳(空)值。
missing當某個值理論上存在、但我們不知道它是什麼時,就會使用 missing。
例如,在統計道路上行駛的車輛時,人工觀察員可能需要休息,或是自動感測器會故障,但車流仍然持續不斷。
因此 missing 是一種佔位符,提醒人們必須決定該如何處理資料中的這個缺口。
julia> mv = [1, 2, missing]
3-element Vector{Union{Missing, Int64}}:
1
2
missing
julia> typeof(mv)
Vector{Union{Missing, Int64}} (alias for Array{Union{Missing, Int64}, 1})
julia> ismissing.(mv) # broadcast function, displays as 1 for true, 0 for false
3-element BitVector:
0
0
1
很少有其他程式語言內建這項功能,但類似的做法有 R 的NA或 SQL 的NULL。
如果運算式中含有 missing 值,通常預設會回傳 missing。
如果你想忽略這些值,可以使用skipmissing()函式明確表達這一點:
julia> mv = [1, 2, missing]
3-element Vector{Union{Missing, Int64}}:
1
2
missing
julia> sum(mv) # missing in, missing out
missing
julia> skipmissing(mv)
skipmissing(Union{Missing, Int64}[1, 2, missing])
julia> collect(skipmissing(mv))
2-element Vector{Int64}:
1
2
julia> sum(skipmissing(mv)) # functions like sum() can work with iterators
3
由於 skipmissing 會建立一個疊代器,如果你需要向量,請用collect()將它包起來。
有時候,用某個預設值取代 missing 值會很有用。
@coalesce()巨集在這方面很有用,它會回傳第一個不是 missing 的值(如果沒有其他值,就回傳 missing)。
julia> str = ["I", "exist", missing]
3-element Vector{Union{Missing, String}}:
"I"
"exist"
missing
julia> [@coalesce(s, "-") for s in str]
3-element Vector{String}:
"I"
"exist"
"-"
NaNNaN 是「非數字」的縮寫,用來標記在預期會出現數字的情況下所發生的計算問題。
julia> v = [0, 1, -1]
3-element Vector{Int64}:
0
1
-1
julia> v / 0
3-element Vector{Float64}:
NaN
Inf
-Inf
julia> sum(v / 0)
NaN
任何對含有 NaN 的資料所做的計算,都會得到 NaN 的結果。
目前沒有專門用來移除 NaN 值的函式,但標準的filter()函式可以很簡單地做到這件事。
只有符合某個指定條件為 true 的值,才會被複製到結果陣列中:
julia> filter(!isnan, [1, 2, NaN])
2-element Vector{Float64}:
1.0
2.0
在這個練習中,你將撰寫程式碼,為工廠員工製作佩戴用的識別證。員工有 ID、姓名和部門名稱。員工識別證的標籤格式如下:"[id] - name - DEPARTMENT"。
實作print_name_badge函式。它會接收 ID、姓名和部門,並回傳識別證標籤,其中部門名稱要轉為大寫。
julia> print_name_badge(67, "Katherine Williams", "Strategic Communication")
"[67] - Katherine Williams - STRATEGIC COMMUNICATION"
由於電腦系統的一個小毛病,新員工剛開始到工廠工作時,有時還沒有 ID。由於識別證是必需品,他們會拿到一張沒有 ID 前綴的臨時識別證。
擴充print_name_badge函式。當 id 缺少時,它應該建立一張沒有 ID 的識別證。
julia> print_name_badge(missing, "Robert Johnson", "Procurement")
"Robert Johnson - PROCUREMENT"
即使是工廠老闆,也必須時時刻刻佩戴識別證。不過,老闆沒有部門,將來也不會有:他們在所有的部門之上。在這種情況下,標籤應該回傳"OWNER",而不是部門名稱。
擴充print_name_badge函式。當部門是nothing時,假設這張識別證屬於公司老闆。
julia> print_name_badge(204, "Rachel Miller", nothing)
"[204] - Rachel Miller - OWNER"
請注意,老闆也有可能同時是新員工。
julia> print_name_badge(missing, "Rachel Miller", nothing)
"Rachel Miller - OWNER"
為了粗略衡量 ID 的發放狀況,你會想看看沒有 ID 的員工的合計薪資。數值很高,代表有很多人還在等待,或是這個問題影響到了資深員工,兩種情況都不妙。
實作salaries_no_id函式,它接收一個 ID 向量和一個對應的薪資向量,並回傳還沒有 ID 的人的薪資總和。這兩個向量的長度相同。
julia> ids = [204, missing, 210, 352, missing, 263]
julia> salaries = [23, 21, 47, 35, 17, 101] * 1000
julia> salaries_no_id(ids, salaries)
38,000