بسیاری از زبانها روشی مانند 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
زبانهای کمی این قابلیت را بهصورت توکار دارند، اما معادلهای نزدیک آن NA در R یا NULL در SQL هستند.
عبارتها معمولاً اگر مقادیر 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] - name - DEPARTMENT".
تابع print_name_badge را پیادهسازی کنید. این تابع باید یک شناسه، یک اسم و یک دپارتمان بگیرد. باید برچسب را برگرداند، با اسم دپارتمان به حروف بزرگ.
julia> print_name_badge(67, "Katherine Williams", "Strategic Communication")
"[67] - Katherine Williams - STRATEGIC COMMUNICATION"
به دلیل یک ایراد عجیب در سیستم رایانهای، کارکنان جدید گاهی وقتی کار در کارخانه را شروع میکنند هنوز شناسه ندارند. چون برچسب الزامی است، یک برچسب موقت بدون پیشوند شناسه دریافت میکنند.
تابع print_name_badge را گسترش دهید. وقتی شناسه missing است، باید برچسبی بدون آن بسازد.
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"
به عنوان یک معیار تقریبی از اینکه شناسهها چقدر خوب صادر میشوند، میخواهید مجموع حقوق کارکنان بدون شناسه را ببینید. مقدار بالا یعنی تعداد زیادی در انتظارند، یا مشکل گریبان افراد باسابقه را گرفته است: هر دو بد است.
تابع salaries_no_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