Parcours
/
Julia
Julia
/
Exercices
/
Observateur d'oiseaux
Observateur d'oiseaux

Observateur d'oiseaux

Exercice d'apprentissage

Introduction

Dans le concept Vectors, on a dit que « les tableaux sont au cœur du langage Julia » et qu'un vecteur est un tableau à une dimension.

Partant de là, on peut raisonnablement espérer que le langage offre de nombreuses façons polyvalentes et puissantes de faire des choses avec les vecteurs, quoi que cela signifie.

Des fonctions qui attendent un vecteur en entrée

Certaines fonctions très simples prennent un vecteur en entrée et renvoient une valeur scalaire.

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

Arithmétique

Suppose que tu aies un vecteur numérique et que tu veuilles soustraire 0,5 à chaque valeur.

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)

Ça échoue, alors et si on soustrayait un autre vecteur ?

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

Ça marche, mais c'est assez fastidieux et gourmand en mémoire à mesure que les vecteurs s'allongent.

Heureusement, Julia a un point « magique » pour résoudre ce problème très simplement : v .- 0.5 est tout ce dont tu as besoin.

La section suivante explique pourquoi.

Broadcasting

Ainsi, v - 0.5 échoue mais v .- 0.5 fonctionne, et il faut comprendre ce que fait ce point.

Deux choses, qui se combinent pour donner le résultat souhaité.

1. Application élément par élément

Premièrement, ajouter un point devant n'importe quel opérateur infixe signifie « appliquer cette opération à chaque élément séparément ».

De même, ajouter un point après le nom d'une fonction la « vectorise », même si cette fonction a été écrite pour des entrées scalaires.

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

2. Expansion des singletons

On a vu dans un exemple précédent que l'on peut soustraire des vecteurs de même longueur, mais comprends bien que .- est un opérateur plus sûr que -, parce qu'il rend explicite l'intention d'opérer élément par élément.

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

Et avec des vecteurs de longueurs différentes ?

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 général, des longueurs différentes provoquent une erreur, sauf quand l'une d'elles vaut 1 (techniquement, une dimension « singleton »).

Les singletons comme [0.5,] ou simplement 0.5 sont automatiquement étendus à la longueur nécessaire par répétition. C'est là le cœur du broadcasting.

Indexation

La sélection d'éléments d'un vecteur par leur numéro d'indice a déjà été abordée dans de précédents concepts.

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

Indexation logique

Il est aussi possible de sélectionner les éléments qui satisfont une certaine expression logique (techniquement, un « prédicat »). Cela nécessite généralement du 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)

Pour des expressions plus complexes, les points ont tendance à se multiplier (mais ils sont petits et faciles à taper).

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)

Pour rappel, le « vecteur » peut en fait être n'importe quel itérable ordonné approprié, comme un intervalle :

julia> n = 3:10
3:10

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

Instructions

Tu es un observateur d'oiseaux passionné qui tiens le compte du nombre d'oiseaux venus dans ton jardin ces sept derniers jours.

Tu as six tâches, qui portent toutes sur le nombre d'oiseaux ayant visité ton jardin.

1. Vérifie combien d'oiseaux sont venus aujourd'hui

Implémente la fonction today() pour qu'elle renvoie le nombre d'oiseaux qui ont visité ton jardin aujourd'hui. Les comptages d'oiseaux sont ordonnés par jour : le premier élément correspond au comptage du jour le plus ancien, et le dernier au comptage d'aujourd'hui.

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

2. Incrémente le comptage d'aujourd'hui

Implémente la fonction increment_todays_count() pour incrémenter le comptage d'aujourd'hui :

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

3. Vérifie s'il y a eu un jour sans aucun oiseau

Implémente la fonction has_day_without_birds() qui renvoie true s'il y a eu un jour où aucun oiseau n'a visité le jardin, et false sinon :

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

4. Calcule le nombre d'oiseaux pour un nombre de jours donné

Implémente la fonction count_for_first_days() qui renvoie le nombre d'oiseaux qui ont visité ton jardin depuis le début de la semaine, mais limite le comptage au nombre de jours spécifié depuis le début de la semaine.

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

5. Calcule le nombre de jours chargés

Certains jours sont plus chargés que d'autres. Un jour chargé est un jour où cinq oiseaux ou plus ont visité ton jardin. Implémente la fonction busy_days() pour qu'elle renvoie le nombre de jours chargés :

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

6. Calcule les moyennes par jour de la semaine

Tu décides d'étendre tes relevés en gardant les comptages de plusieurs semaines. Dans chaque cas, les comptages sont classés par jour de la semaine, du lundi comme première entrée au dimanche comme dernière.

Implémente la fonction average_per_day() qui renvoie la moyenne sur 2 semaines.

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]
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Julia Exercism

Prêt à commencer Observateur d'oiseaux ?

Inscris-toi sur Exercism pour apprendre et maîtriser Julia avec 35 concepts128 exercices, et un vrai mentorat humain, le tout gratuitement.