1000까지의 모든 음이 아닌 정수가 필요하다고 해봐요. 이걸 배열에 일일이 입력해야 한다면 얼마나 우스꽝스러울까요.
이럴 때 쓰는 게 바로 range 타입이에요:
julia> 0:1000
0:1000
julia> typeof(0:1000)
UnitRange{Int64}
range는 아주 흔해요. 입력을 줄여 주는 용도뿐만 아니라 함수의 반환 타입으로도 쓰여요.
range는 배열이 아니라는 점에 주의해요.
배열은 처음에 정의되고("탐욕적" 평가), 배열 길이에 비례하는 저장 공간이 필요해요.
반대로 range는 시퀀스를 생성하기 위한 명령의 집합일 뿐이에요("지연" 평가, 또는 "이터레이터").
range를 배열로 써야 한다면 collect() 함수로 변환해요:
julia> collect(0:5)
6-element Vector{Int64}:
0
1
2
3
4
5
선택적으로 collect(type, range)를 써서 출력 배열의 타입을 지정할 수도 있어요.
스텝 크기도 지정할 수 있는데, 여기서는 0.3이에요:
julia> collect(1.0:0.3:2.0)
4-element Vector{Float64}:
1.0
1.3
1.6
1.9
즉, 문법은 start:stepsize:stop이에요.
정수 예시에서 봤듯이 양 끝값은 모두 _포함_돼요.
스텝 크기가 stop - start를 정확히 나누지 않으면, 마지막 원소는 stop을 넘지 않아요.
더 세밀하게 제어하려면 옵션이 더 많은 Base.range() 함수를 사용해요.
숫자가 아닌 시퀀스도 range에 사용할 수 있어요. 가장 간단한 예는 ASCII 문자예요:
julia> 'a':'d'
'a':1:'d'
julia> typeof('a':'d')
StepRange{Char, Int64}
julia> collect('a':'d')
4-element Vector{Char}:
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
Char 타입은 다른 개념에서 더 자세히 다뤄요.
지금은 그냥 작은따옴표로 감싼 단일 문자라고 생각해요.
first()와 last()로 range의 양 끝값을 확인해요.
어떤 값이 range에 포함되는지 확인하는 것은 자주 유용해요.
이를 위한 기반 함수는 in()이지만, 중위 연산자 in이나 더 수학적인 동의어인 ∈를 더 자주 사용해요.
적절한 편집기에서는 ∈의 단축키가 \in을 입력한 뒤 tab을 누르는 것이에요.
r = 1:10 # => 1:10
first(r) # => 1
last(r) # => 10
7 in r # => true
11 ∈ r # => false
in 또는 ∈ 연산자는 여기서는 range와 함께 사용했지만, 벡터, 집합, 딕셔너리 같은 여러 다른 컬렉션 타입과도 사용할 수 있어요.
배열 인덱싱에는 정수 range와 배열을 사용할 수 있어요:
nums = collect(10.0:50.0)
nums[3:2:7] # gives [12.0, 14.0, 16.0]
nums[ [3, 5, 7] ] # also gives [12.0, 14.0, 16.0]
end와 함께 쓰는 것도 가능하지만, 연산자 우선순위 때문에 괄호가 필요할 수 있어요:
nums[(end - 3):end]
4-element Vector{Float64}:
47.0
48.0
49.0
50.0
물론 인덱스 원소는 이미 존재하는 정수 변수여도 돼요.