Percursos
/
Julia
Julia
/
Exercícios
/
Observador de aves
Observador de aves

Observador de aves

Exercício de aprendizagem

Introdução

No Conceito Vectors, dissemos que «os arrays estão no coração da linguagem Julia» e que um vetor é unidimensional.

Assim sendo, é razoável esperar que a linguagem ofereça muitas formas versáteis e poderosas de fazer coisas com vetores, seja lá o que isso for.

Funções que esperam um vetor como parâmetro de entrada

Algumas funções muito simples recebem um vetor como parâmetro de entrada e devolvem um valor escalar.

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

Aritmética

Suponhamos que tens um vetor numérico e queres subtrair 0.5 a cada valor.

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)

Isso falha, então e se subtraíres outro vetor?

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

Funciona, mas torna-se bastante maçador e exige muita memória à medida que os vetores ficam maiores.

Felizmente, a Julia tem um ponto «mágico» que resolve este problema de forma muito simples: só precisas de v .- 0.5.

A secção seguinte explica porquê.

Broadcasting

Então, v - 0.5 falha, mas v .- 0.5 funciona, e precisamos de perceber o que faz o ponto.

Duas coisas, que se combinam para dar o resultado desejado.

1. Aplicação elemento a elemento

Primeiro, colocar um ponto antes de qualquer operador infixo significa «aplicar esta operação a cada elemento separadamente».

Da mesma forma, colocar um ponto depois do nome de uma função «vetoriza-a», mesmo que a função tenha sido escrita para parâmetros de entrada escalares.

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

2. Expansão de singletons

Vimos num exemplo anterior que podemos subtrair vetores com o mesmo comprimento, mas convém perceberes que .- é um operador mais seguro do que -, porque deixa clara a intenção de operar elemento a elemento.

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

E quanto a vetores com comprimentos diferentes?

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

Em geral, comprimentos diferentes são um erro, exceto quando um deles tem comprimento 1 (tecnicamente, uma dimensão «singleton»).

Os singletons como [0.5,] ou apenas 0.5 são expandidos automaticamente até ao comprimento necessário, por repetição. É isto que está no coração do broadcasting.

Indexação

A seleção de elementos de um vetor por número de índice já foi abordada em Conceitos anteriores.

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']

Indexação lógica

Também é possível selecionar elementos que satisfazem determinada expressão lógica (tecnicamente, um «predicado»). Normalmente, isso exige broadcasting.

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)

Em expressões mais complexas, os pontos tendem a multiplicar-se (mas são pequenos e fáceis de escrever).

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)

Lembra-te de que o «vetor» pode, na verdade, ser qualquer iterável ordenado adequado, como um intervalo:

julia> n = 3:10
3:10

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

Instruções

És um observador de aves ávido que regista quantas aves visitaram o teu jardim nos últimos sete dias.

Tens seis tarefas, todas relacionadas com o número de aves que visitaram o teu jardim.

1. Verifica quantas aves visitaram o jardim hoje

Implementa a função today() para devolver quantas aves visitaram o teu jardim hoje. As contagens de aves estão ordenadas por dia: o primeiro elemento é a contagem do dia mais antigo e o último é a contagem de hoje.

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

2. Incrementa a contagem de hoje

Implementa a função increment_todays_count() para incrementar a contagem de hoje:

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

3. Verifica se houve um dia sem aves

Implementa a função has_day_without_birds() que devolve true se houve um dia em que zero aves visitaram o jardim; caso contrário, devolve false:

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

4. Calcula o número de aves nos primeiros dias

Implementa a função count_for_first_days() que devolve o número de aves que visitaram o teu jardim desde o início da semana, mas limita a contagem ao número de dias indicado a partir do início da semana.

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

5. Calcula o número de dias movimentados

Há dias mais movimentados do que outros. Um dia movimentado é aquele em que cinco ou mais aves visitaram o teu jardim. Implementa a função busy_days() para devolver o número de dias movimentados:

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

6. Calcula as médias por dia da semana

Decides ampliar os teus registos, guardando contagens de várias semanas. Em cada caso, as contagens estão organizadas por dia da semana, de segunda-feira como primeira entrada a domingo como última.

Implementa a função average_per_day() que devolve a média de 2 semanas.

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]
Editar via GitHub A ligação abre numa nova janela ou separador
Julia Exercism

Estás pronto para começar Observador de aves?

Inscreve-te no Exercism para aprenderes e dominares Julia com 35 conceitos128 exercícios, e mentoria humana real, tudo grátis.