轨道
/
Julia
Julia
/
练习
/
姓名牌
姓名牌

姓名牌

学习练习

简介

许多语言都有类似 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 是“Not a Number”的缩写,它标记的是在期望得到数字的情况下出现的计算问题。

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,全部免费。