Tuple在很多方面跟Vector(一维array)很像。不过,两者之间也有几处重要的不同。
( )书写,而不是方括号[ ];不过在含义明确的情况下,圆括号可以省略。不可变性让编译器能做更多优化,也让元组的性能优于向量,所以在不需要可变性的情况下应该优先使用元组。
julia> t = (3, 5.2, "xyz")
(3, 5.2, "xyz")
# Non-homogeneous:
julia> dump(t)
Tuple{Int64, Float64, String}
1: Int64 3
2: Float64 5.2
3: String "xyz"
julia> t[2]
5.2
# Immutable:
julia> t[2] = 7.3
ERROR: MethodError: no method matching setindex!(::Tuple{Int64, Float64, String})
还有一个Tuple()构造函数,可以把任何可迭代集合变成元组。很方便的是,它会把字符串视为由字符组成的可迭代集合。
julia> Tuple("Julia")
('J', 'u', 'l', 'i', 'a')
对任何元组,都可以通过下标访问元素,或者对它们进行循环。
任何纯数值元组都能用在sum()这类数学函数中,和数组完全一样。
使用多重赋值可以把元组解包成一个个独立的元素。对于不需要的元素,用下划线_作为占位变量。
julia> tup = (1, "Julia", true)
(1, "Julia", true)
julia> num, name, _ = tup
(1, "Julia", true)
julia> uppercase(name), 2num
("JULIA", 2)
Python 程序员对这种多重赋值语法会非常熟悉。
Tuple只包含值。NamedTuple则把每个值和一个名字配对。
这样就能用“点”表示法访问各个字段:
julia> nt = (a = 1, b = 7.3)
(a = 1, b = 7.3)
julia> dump(nt)
@NamedTuple{a::Int64, b::Float64}
a: Int64 1
b: Float64 7.3
julia> nt.b
7.3
名字在内部以Symbol的形式存储(一种不可变类型,前面带一个冒号:),所以还有另一种可用的语法:
julia> nt[:b]
7.3
要分别取出名字(也叫“键”)或值都很容易:
julia> nt
(a = 1, b = 7.3)
julia> keys(nt)
(:a, :b)
julia> values(nt)
(1, 7.3)
注意,遍历具名元组时只会产生_值_,_名字_会被忽略。
元组(无论是否具名)都是把结构化数据传入和传出函数的常见方式。在这种场景下,不可变性很有好处,它既能保证数据安全,也能让编译器进行更激进的优化。
Azara 和 Rui 是队友,正在参加一场海盗主题的寻宝比赛。一个人拿着一份带地图坐标的宝藏清单,另一个人拿着一份带地图坐标的地点名称清单。他们还拿到了空白地图,上面的起点标着“你在这里”。
| Azara 的清单 | Rui 的清单 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
不过事情有点乱:Azara 的坐标格式和排序似乎与 Rui 的不同,他们得不停地在两份清单之间来回对照,才能弄清楚哪个宝藏对应哪个地点。 作为初学 Julia 的程序员,他们来找你帮忙写一个小程序(其实是一组函数),好把寻宝信息整理得更清楚。
实现get_cooordinate()函数,它接收 Azara 清单中的一个(treasure, coordinate)对,只返回提取出来的地图坐标。
julia> get_cooordinate( ("Scrimshaw Whale's Tooth", "2A") )
"2A"
实现convert_coordinate()函数,它接收一个 "2A" 格式的坐标,返回一个('2', 'A')格式的元组。
julia> convert_coordinate("2A")
('2', 'A')
实现compare_records()函数,它接收一个(treasure, coordinate)对和一个(location, coordinate, quadrant)记录,并比较双方的坐标。
如果坐标“匹配”,返回 true;如果不匹配,返回 false。
为准确比较,按需重新格式化坐标。
julia> compare_records(("Brass Spyglass", "4B"), ("Seaside Cottages", ('1', 'C'), "blue"))
false
julia> compare_records(("Model Ship in Large Bottle", "8A"), ("Harbor Managers Office", ('8', 'A'), "purple"))
true
实现create_record()函数,它接收 Azara 清单中的一个(treasure, coordinate)对和 Rui 清单中的一个(location, coordinate, quadrant)记录,如果坐标匹配,就返回(coordinate, location, quadrant, treasure)。
如果坐标_不_匹配,返回一个空元组。 为准确比较,按需重新格式化坐标。
julia> create_record(("Brass Spyglass", "4B"), ("Abandoned Lighthouse", ('4', 'B'), "Blue"))
("4B", "Abandoned Lighthouse", "Blue", "Brass Spyglass")
julia> create_record(("Brass Spyglass", "4B"), ("Seaside Cottages", ('1', 'C'), "Blue"))
()