元组

元组 属于 Julia

1 个练习

关于 元组

一个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)

要把一个元组的所有元素复制到另一个元组(更一般地说,是一个集合)里,可以用splat运算符...把它解包。这一点会在函数概念里更详细地介绍。

julia> new_tup = (tup..., π, '😊')
(1, "Julia", true, π, '😊')

具名元组

一个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

有时把具名元组的创建拆成两步会很有用:

  1. 把这些字段定义成一个自定义数据类型。
  2. 用它作为构造函数,把元组转换成具名元组。
# Step 1
julia> Student = NamedTuple{(:name, :grade), Tuple{String, Int}}
@NamedTuple{name::String, grade::Int64}

julia> typeof(Student)
DataType

# Step 2
julia> s = Student( ("Helen", 3) )
(name = "Helen", grade = 3)

julia> dump(s)
@NamedTuple{name::String, grade::Int64}
  name: String "Helen"
  grade: Int64 3

创建具名元组的方法多得出人意料,如果感兴趣,可以查阅文档。

单独取出名字(也叫“键”)或值都很容易:

julia> keys(s)
(:name, :grade)

julia> values(s)
("Helen", 3)

注意,对具名元组进行迭代只会产生_值_,_名字_会被忽略。

如果迭代时名字也有用,就需要更多步骤。 可以把NamedTuple转换成一个由Pairs组成的Vector(Pair是另一个概念的主题)。

julia> pairs(s)
pairs(::NamedTuple) with 2 entries:
  :name  => "Helen"
  :grade => 3

julia> collect(pairs(s))
2-element Vector{Pair{Symbol, Any}}:
  :name => "Helen"
  :grade => 3

因此,具名元组很像字典。不过,它与 Julia 里的[Dict][dict]在一些重要方面有所不同:

  • Dict是可变的;而NamedTuple和任何元组一样,是不可变的。
  • Dict在接受键的类型上很灵活;NamedTuple只能用符号作为键。

元组(无论是否具名)是在函数之间来回传递结构化数据的常见方式。在这种场景下,不可变性是好事,它提供了数据安全性,也让编译器可以做更激进的优化。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 元组