元組

元組 在 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則只能使用Symbol當作鍵。

元組(無論具名與否)是把結構化資料傳入函式、從函式傳出的常見方式。在這個用途上,不可變性很有好處,既能保障資料安全,也能讓編譯器進行更積極的最佳化。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 元組