logo

줄리아에서 벡터와 튜플의 차이점 📂줄리아

줄리아에서 벡터와 튜플의 차이점

설명

벡터와 튜플은 얼핏보면 비슷해보이고, 실제로 공통점도 여럿 있기에 "같은 개념인데 이름만 다른건가?"하는 생각이 드는 건 자연스럽다. 하지만 벡터와 튜플은 몇 가지 중요한 차이점이 있다.

이 글에서는 주로 실제로 코드를 작성하고 사용하는 관점에서의 공통점과 차이점에 집중할 것이다. 줄리아에서 튜플이 어떤 수학적 근거를 가지고 있으며, 이것이 벡터(리스트)와 어떻게 다른지에 대해서는 책 줄리아 프로그래밍의 $3.2.2$ 튜플에서 상세히 설명하였다.

공통점

여러 원소를 포함할 수 있으며 인덱싱과 슬라이싱이 가능하다는 정도만이 벡터와 튜플의 공통점이다.

원소

벡터와 튜플은 모두 여러 개의 원소를 가질 수 있다.

julia> v = [1, 2, 3]
3-element Vector{Int64}:
 1
 2
 3

julia> t = (1, 2, 3)
(1, 2, 3)

인덱싱

벡터와 튜플은 모두 인덱싱을 통해 원소에 접근할 수 있다.

julia> v[1]
1

julia> t[1]
1

슬라이싱

벡터와 튜플은 모두 슬라이싱이 가능하다.

julia> v[1:2]
2-element Vector{Int64}:
 1
 2

julia> t[1:2]
(1, 2)

차이점

불변성

튜플은 불변immutable하다. 즉, 튜플의 원소를 변경할 수 없다.

julia> v[1] = 10
10

julia> v
3-element Vector{Int64}:
 10
  2
  3

julia> t[1] = 10
ERROR: MethodError: no method matching setindex!(::Tuple{Int64, Int64, Int64}, ::Int64, ::Int64)

표기법

벡터는 대괄호 []를 사용하여 표기하고, 튜플은 소괄호 ()를 사용하여 표기한다. 벡터는 쉼표를 생략해도 되지만, 튜플은 쉼표를 생략하면 안된다. 오히려 튜플은 소괄호를 생략할 수 있다. 또한 벡터의 경우 쉼표를 생략하면 행벡터가 된다.

julia> [1 2 3]
1×3 Matrix{Int64}:
 1  2  3

julia> (1 2 3)
ERROR: ParseError:
# Error @ REPL[16]:1:4
(1 2 3)
#  └─┘ ── Expected `)`

julia> 1, 2, 3
(1, 2, 3)

모양

벡터는 모양을 바꿀 수 있지만, 튜플은 불가능하다.

julia> u = [1, 2, 3, 4, 5, 6]
6-element Vector{Int64}:
 1
 2
 3
 4
 5
 6

julia> reshape(u, 1, 6)
1×6 Matrix{Int64}:
 1  2  3  4  5  6

julia> reshape(u, 2, 3)
2×3 Matrix{Int64}:
 1  3  5
 2  4  6

julia> reshape(u, 3, 2)
3×2 Matrix{Int64}:
 1  4
 2  5
 3  6

julia> reshape(t, 3, 1)
ERROR: MethodError: no method matching reshape(::Tuple{Int64, Int64, Int64}, ::Int64, ::Int64)

속도1

튜플은 불변이기 때문에 벡터보다 더 빠르다. 따라서 원소를 바꿀 일이 없고, 원소의 수가 적다면 튜플을 사용하는 것이 유리하다. 다만 반대로 크기가 큰 상황일 때는 벡터가 훨씬 유리하다.

julia> using BenchmarkTools

julia> @benchmark (1, 2, 3)
BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max):  0.700 ns … 5.600 ns  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     0.700 ns             ┊ GC (median):    0.00%
 Time  (mean ± σ):   0.741 ns ± 0.099 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

  █                                                       ▂
  █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█ ▂
  0.7 ns         Histogram: frequency by time        0.8 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark [1, 2, 3]
BenchmarkTools.Trial: 10000 samples with 999 evaluations.
 Range (min … max):  13.514 ns …  1.907 μs  ┊ GC (min … max):  0.00% … 98.16%
 Time  (median):     16.817 ns              ┊ GC (median):     0.00%
 Time  (mean ± σ):   20.538 ns ± 64.293 ns  ┊ GC (mean ± σ):  12.68% ±  4.04%

        ▄▄█▄▆▁▁
  ▂▂▃▃▆▇███████▆▆▄▄▃▃▃▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▃▃▃▃▂▂▂▂▂▂▁▂▂ ▃
  13.5 ns         Histogram: frequency by time        34.1 ns <

 Memory estimate: 80 bytes, allocs estimate: 1.

타입 승격

벡터를 정의할 때는 타입 승격이 기본적으로 적용되지만, 튜플은 그렇지 않다. 12.0으로 벡터와 튜플을 정의하면 벡터는 원소의 타입이 Float64로 맞춰진다.

julia> [1, 2.0]
2-element Vector{Float64}:
 1.0
 2.0

julia> Any[1, 2.0]
2-element Vector{Any}:
 1
 2.0

julia> (1, 2.0)
(1, 2.0)

  1. Bogumił Kamiński, 데이터 분석을 위한 줄리아(Julia for Data Analysis, 류현지 역), p88 ↩︎