名牌

名牌

學習練習

簡介

許多程式語言都有類似 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"
 "-"

NaN

NaN 是「非數字」的縮寫,用來標記在預期會出現數字的情況下所發生的計算問題。

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"。

1. 建立員工的識別證

實作print_name_badge函式。它會接收 ID、姓名和部門,並回傳識別證標籤,其中部門名稱要轉為大寫。

julia> print_name_badge(67, "Katherine Williams", "Strategic Communication")
"[67] - Katherine Williams - STRATEGIC COMMUNICATION"

2. 建立新員工的識別證

由於電腦系統的一個小毛病,新員工剛開始到工廠工作時,有時還沒有 ID。由於識別證是必需品,他們會拿到一張沒有 ID 前綴的臨時識別證。

擴充print_name_badge函式。當 id 缺少時,它應該建立一張沒有 ID 的識別證。

julia> print_name_badge(missing, "Robert Johnson", "Procurement")
"Robert Johnson - PROCUREMENT"

3. 建立老闆的識別證

即使是工廠老闆,也必須時時刻刻佩戴識別證。不過,老闆沒有部門,將來也不會有:他們在所有的部門之上。在這種情況下,標籤應該回傳"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"

4. 計算沒有 ID 的員工的總薪資

為了粗略衡量 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
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Julia Exercism

準備好開始 名牌 了嗎?

註冊 Exercism,透過 35 個概念128 個練習 和真人引導來學習並精通 Julia,全部免費。