트랙
/
Julia
Julia
/
연습 문제
/
새 관찰자
새 관찰자

새 관찰자

학습 연습 문제

소개

Vectors 개념에서 "배열은 Julia 언어의 핵심"이라고 했고, 벡터는 1차원이라고 했어요.

그렇다면 Julia가 벡터로 무언가를 하는 다양하고 강력한 방법을 많이 제공할 것이라고 기대하는 것도 당연해요. 그게 무슨 뜻이든 말이죠.

벡터를 입력으로 받는 함수

아주 단순한 함수 중에는 벡터를 입력으로 받아 스칼라를 반환하는 것도 있어요.

v = [2, 3, 4]
length(v)  # => 3
sum(v)  # => 9

산술 연산

숫자로 이루어진 벡터가 있고, 각 값에서 0.5를 빼고 싶다고 해봐요.

julia> v = [1.2, 1.5, 1.7]
3-element Vector{Float64}:
 1.2
 1.5
 1.7

julia> v - 0.5
ERROR: MethodError: no method matching -(::Vector{Float64}, ::Float64)

이건 실패해요. 그럼 다른 벡터를 빼면 어떨까요?

julia> v - [0.5, 0.5, 0.5]
3-element Vector{Float64}:
 0.7
 1.0
 1.2

성공하지만, 벡터가 길어질수록 꽤 번거롭고 메모리도 많이 잡아먹어요.

다행히도 Julia에는 이 문제를 아주 간단히 해결해 주는 "마법의" 점이 있어요. v .- 0.5만 쓰면 돼요.

그 이유는 다음 절에서 설명해요.

브로드캐스팅

그래서 v - 0.5는 실패하고 v .- 0.5는 성공하는데, 이 점이 도대체 무슨 일을 하는지 이해할 필요가 있어요.

두 가지 일을 하는데, 이 둘이 합쳐져서 원하는 결과를 만들어요.

1. 원소별 적용

먼저, 중위 연산자 앞에 점을 붙이면 "이 연산을 각 원소에 따로 적용하라"는 뜻이에요.

마찬가지로 함수 이름 뒤에 점을 붙이면 그 함수가 벡터화돼요. 그 함수가 스칼라 입력을 위해 작성되었더라도 말이죠.

julia> sqrt.([1, 4, 9])
3-element Vector{Float64}:
 1.0
 2.0
 3.0

2. 싱글턴 확장

앞선 예제에서 길이가 같은 벡터끼리는 뺄 수 있다는 걸 봤어요. 다만 .-는 원소별로 적용하려는 의도를 분명히 드러내기 때문에 -보다 더 안전한 연산자라는 점을 기억해 두세요.

julia> v .- [0.5, 0.5, 0.5]
3-element Vector{Float64}:
 0.7
 1.0
 1.2

길이가 다른 벡터라면 어떨까요?

julia> v .- [0.5, 0.5]
ERROR: DimensionMismatch: arrays could not be broadcast to a common size

julia> v .- [0.5,]
3-element Vector{Float64}:
 0.7
 1.0
 1.2

일반적으로 길이가 다르면 오류예요. 다만 한쪽 길이가 1일 때는 _예외_인데, 엄밀히 말하면 "싱글턴" 차원일 때예요.

[0.5,]나 그냥 0.5 같은 싱글턴은 반복을 통해 필요한 길이로 자동으로 확장돼요. 바로 이게 broadcasting의 핵심이에요.

인덱싱

인덱스 번호로 벡터의 원소를 선택하는 방법은 이전 개념에서 다뤘어요.

a = collect('A':'Z')  # => 26-element Vector{Char}

# index with an integer
a[2]  # => 'B'

# index with a range
 a[12:2:18]  # => ['L', 'N', 'P, 'R']
 
 # index with another vector
 a[ [1, 3, 5] ]  # => ['A', 'C', 'E']

논리 인덱싱

어떤 논리식(엄밀히는 "술어")을 만족하는 원소를 선택할 수도 있어요. 보통은 브로드캐스팅이 필요해요.

julia> a[a .< 'D']
3-element Vector{Char}:
 'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
 'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
 'C': ASCII/Unicode U+0043 (category Lu: Letter, uppercase)

표현이 더 복잡해지면 점이 자꾸 늘어나요. 하지만 점은 작고 입력하기 쉬워요.

julia> a[a .< 'D' .|| a .> 'W']
6-element Vector{Char}:
 'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
 'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
 'C': ASCII/Unicode U+0043 (category Lu: Letter, uppercase)
 'X': ASCII/Unicode U+0058 (category Lu: Letter, uppercase)
 'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
 'Z': ASCII/Unicode U+005A (category Lu: Letter, uppercase)

참고로 "벡터"는 사실 범위(range)처럼 순서가 있는 적절한 반복 가능 객체라면 무엇이든 될 수 있어요.

julia> n = 3:10
3:10

julia> n[isodd.(n)]
4-element Vector{Int64}:
 3
 5
 7
 9

지침

지난 7일 동안 정원에 새가 몇 마리 찾아왔는지 기록하는 열렬한 새 관찰자예요.

여섯 개의 과제가 있는데, 모두 정원에 찾아온 새의 수를 다뤄요.

1. 오늘 몇 마리의 새가 찾아왔는지 확인하기

today() 함수를 구현해서 오늘 정원에 새가 몇 마리 찾아왔는지 반환해요. 새의 수는 날짜 순으로 나열되어 있는데, 첫 번째 원소는 가장 오래된 날의 수이고 마지막 원소는 오늘의 수예요.

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> today(birds_per_day)
1

2. 오늘의 수 늘리기

increment_todays_count() 함수를 구현해서 오늘의 수를 늘려요:

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> increment_todays_count(birds_per_day)
[2, 5, 0, 7, 4, 2]

3. 새가 찾아오지 않은 날이 있었는지 확인하기

정원에 새가 한 마리도 찾아오지 않은 날이 있었다면 true를, 그렇지 않다면 false를 반환하는 has_day_without_birds() 함수를 구현해요:

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> has_day_without_birds(birds_per_day)
true

4. 처음 며칠 동안 찾아온 새의 수 계산하기

count_for_first_days() 함수를 구현해요. 이 함수는 주의 시작부터 정원에 찾아온 새의 수를 반환하는데, 주의 시작부터 지정한 날짜 수까지만 세요.

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> count_for_first_days(birds_per_day, 4)
14

5. 바쁜 날의 수 계산하기

어떤 날은 다른 날보다 더 바빠요. 바쁜 날은 정원에 다섯 마리 이상의 새가 찾아온 날이에요. busy_days() 함수를 구현해서 바쁜 날의 수를 반환해요:

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> busy_days(birds_per_day)
2

6. 요일별 평균 계산하기

여러 주에 걸쳐 수를 기록해서 기록을 확장하기로 했어요. 각 주의 수는 요일 순으로 나열되어 있는데, 월요일이 첫 번째 항목이고 일요일이 마지막이에요.

2주간의 평균을 반환하는 average_per_day() 함수를 구현해요.

julia> week1 = [7, 2, 9, 1, 3, 0, 10]
julia> week2 = [2, 6, 4, 1, 3, 8, 9]
julia> average_per_day(week1, week2)
[4.5, 4.0, 6.5, 1.0, 4.0, 3.0, 9.5]
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Julia Exercism

새 관찰자 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Julia 트랙을 개념 35개연습 문제 128개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.