Багато мов мають спосіб на кшталт 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"
"-"
NaNСкорочення від «Not a Number» («не число»), 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] - name - DEPARTMENT".
Реалізуйте функцію print_name_badge. Вона повинна приймати ідентифікатор, імʼя та відділ. Вона повинна повертати етикетку бейджа, де назва відділу записана у верхньому регістрі.
julia> print_name_badge(67, "Katherine Williams", "Strategic Communication")
"[67] - Katherine Williams - STRATEGIC COMMUNICATION"
Через особливість компʼютерної системи нові працівники іноді ще не мають ідентифікатора, коли починають працювати на фабриці. Оскільки бейджі обовʼязкові, вони отримають тимчасовий бейдж без префікса з ідентифікатором.
Розширте функцію print_name_badge. Коли ідентифікатор відсутній, вона повинна створити бейдж без нього.
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
Зареєструйтеся на Exercism, щоб вивчати й опановувати Julia, а також 35 концепцій128 вправ та справжнє наставництво від людей, і все це безкоштовно.