Rutas
/
Julia
Julia
/
Ejercicios
/
Observador de pájaros
Observador de pájaros

Observador de pájaros

Ejercicio de aprendizaje

Introducción

En el concepto Vectors, dijimos que «los arrays están en el corazón del lenguaje Julia» y que un vector es unidimensional.

Teniendo esto en cuenta, es razonable esperar que el lenguaje ofrezca muchas formas versátiles y potentes de hacer cosas con vectores, sea lo que sea que eso signifique.

Funciones que esperan un vector como entrada

Algunas funciones muy sencillas reciben un vector como entrada y devuelven un valor escalar como salida.

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

Aritmética

Supón que tienes un vector numérico y quieres restar 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)

Eso falla, así que ¿qué pasa si restamos otro vector?

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

Funciona, pero resulta bastante tedioso y consume mucha memoria a medida que los vectores se alargan.

Por suerte, Julia tiene un punto «mágico» que resuelve este problema de forma muy sencilla: v .- 0.5 es todo lo que necesitas.

La siguiente sección explica por qué.

Broadcasting

Así que v - 0.5 falla, pero v .- 0.5 funciona, y necesitamos entender qué hace el punto.

Dos cosas, que se combinan para dar el resultado deseado.

1. Aplicación elemento a elemento

En primer lugar, añadir un punto delante de cualquier operador infijo significa «aplicar esta operación a cada elemento por separado».

De forma similar, añadir un punto después del nombre de una función la «vectoriza», aunque la función se haya escrito para entradas escalares.

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

2. Expansión de singleton

En un ejemplo anterior vimos que podemos restar vectores de la misma longitud, aunque conviene entender que .- es un operador más seguro que -, porque deja clara la intención de operar elemento a elemento.

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

¿Y si los vectores tienen longitudes distintas?

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

En general, que las longitudes no coincidan es un error, excepto cuando una tiene longitud 1 (técnicamente, una dimensión «singleton»).

Los singleton como [0.5,] o simplemente 0.5 se expanden automáticamente a la longitud necesaria mediante repetición. Esto es el núcleo de broadcasting.

Indexación

La selección de elementos de un vector por número de índice se ha tratado en conceptos 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']

Indexación lógica

También es posible seleccionar elementos que satisfacen cierta expresión lógica (técnicamente, un «predicado»). Esto suele requerir 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)

En expresiones más complejas, los puntos tienden a multiplicarse (pero son pequeños y fáciles de escribir).

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)

Recuerda que el «vector» puede ser, de hecho, cualquier iterable ordenado adecuado, como un rango:

julia> n = 3:10
3:10

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

Instrucciones

Eres un entusiasta observador de aves que lleva un registro de cuántos pájaros han visitado tu jardín en los últimos siete días.

Tienes seis tareas, todas relacionadas con el número de pájaros que han visitado tu jardín.

1. Comprueba cuántos pájaros han visitado hoy tu jardín

Implementa la función today() para que devuelva cuántos pájaros han visitado hoy tu jardín. Los recuentos de pájaros están ordenados por día: el primer elemento es el recuento del día más antiguo y el último es el de hoy.

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

2. Incrementa el recuento de hoy

Implementa la función increment_todays_count() para incrementar el recuento de hoy:

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

3. Comprueba si hubo un día sin pájaros visitantes

Implementa la función has_day_without_birds() que devuelve true si hubo un día en el que ningún pájaro visitó el jardín; en caso contrario, devuelve false:

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

4. Calcula el número de pájaros visitantes durante los primeros días

Implementa la función count_for_first_days() que devuelve el número de pájaros que han visitado tu jardín desde el comienzo de la semana, pero limita el recuento al número de días indicado desde el comienzo de la semana.

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

5. Calcula el número de días ajetreados

Algunos días están más ajetreados que otros. Un día ajetreado es aquel en el que cinco o más pájaros han visitado tu jardín. Implementa la función busy_days() para que devuelva el número de días ajetreados:

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

6. Calcula las medias por día de la semana

Decides ampliar tus registros guardando los recuentos de varias semanas. En cada caso, los recuentos están ordenados por día de la semana, desde el lunes como primera entrada hasta el domingo como última.

Implementa la función average_per_day() que devuelve la media 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 en GitHub El enlace se abre en una ventana o pestaña nueva
Julia Exercism

¿Listo para empezar Observador de pájaros?

Regístrate en Exercism para aprender y dominar Julia con 35 conceptos128 ejercicios y mentoría humana real, todo gratis.