Parcours
/
Julia
Julia
/
Exercices
/
Suggestions de la boutique
Suggestions de la boutique

Suggestions de la boutique

Exercice d'apprentissage

Introduction

Toute personne ayant utilisé Python a presque certainement utilisé des compréhensions de listes, qui sont au cœur de la syntaxe de Python depuis les premières versions.

Une fonctionnalité aussi pratique finit peu à peu par se frayer un chemin dans d'autres langages, dont Julia.

Pour les programmeurs Julia, les compréhensions sont une option plutôt qu'une nécessité, car il existe généralement des alternatives (broadcasting, fonctions d'ordre supérieur, etc.).

Cependant, une compréhension offre souvent un moyen simple, lisible et performant de construire un tableau. Son usage relève en fin de compte du goût personnel, et de ton rapport à Python par opposition aux langages fonctionnels.

La syntaxe est pour l'essentiel une copie directe de celle de Python, mais avec des extensions pour les tableaux de dimension supérieure.

Une seule variable

Très pythonique, y compris la clause if optionnelle.

julia> [x^2 for x in 1:3]
3-element Vector{Int64}:
 1
 4
 9
julia> [x^2 for x in 1:3 if isodd(x^2)]
2-element Vector{Int64}:
 1
 9

La forme de la sortie dépend des détails de la compréhension : elle est généralement identique à celle de la collection d'entrée dans les cas simples, mais aplatie en un Vector par une clause if.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x^2 for x in m]
2×3 Matrix{Int64}:
  1   4   9
 16  25  36
julia> [x^2 for x in m if isodd(x^2)] 
3-element Vector{Int64}:
  1
 25
  9

Plusieurs variables, sortie en Vector

Comme en Python, on peut avoir plusieurs clauses for avec des variables différentes, sur des collections d'entrée identiques ou différentes.

julia> [x * y for x in 1:3 for y in 4:6]
9-element Vector{Int64}:
  4
  5
  6
  8
 10
 12
 12
 15
 18
julia> [x * y for x in 1:3 for y in 4:6 if isodd(x * y)]
2-element Vector{Int64}:
  5
 15

Cela équivaut à des boucles imbriquées. La sortie est unidimensionnelle, même avec une matrice en entrée.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x*y for x in m for y in m]
36-element Vector{Int64}:
  1
  4
  2
  5
(truncated output...)

Plusieurs variables, sortie multidimensionnelle

La section précédente décrivait plusieurs clauses for séparées uniquement par des espaces.

Dans cette section, il n'y a qu'un seul for et les variables sont séparées par des virgules.

julia> [(x, y) for x in 1:3, y in 4:6]
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)

Chaque variable de la compréhension crée une nouvelle dimension dans la sortie, avec un élément pour chaque combinaison possible des variables.

Dans l'exemple ci-dessus, x augmente en descendant le long des lignes, y augmente en parcourant les colonnes. Des dimensions supérieures sont possibles, avec les avertissements habituels sur la lisibilité de la sortie.

Expressions génératrices

Les sections précédentes se sont concentrées sur la sortie sous forme de tableau, avec la compréhension placée entre crochets [ ... ].

Quand on remplace les crochets par des parenthèses ( ... ), il se passe quelque chose de différent : on obtient une generator expression, c'est-à-dire un itérateur évalué paresseusement qui peut produire la valeur suivante à la demande.

julia> g = ((x, y) for x in 1:3, y in 4:6)
Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}, var"#9#10"}(var"#9#10"(), Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:3, 4:6)))
# Indexing fails with a generator, the entries don't exist yet
julia> g[1, 2]
ERROR: MethodError: no method matching getindex(::Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{…}, UnitRange{…}}}, var"#9#10"}, ::Int64, ::Int64)
# conversion to array
julia> collect(g)
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)
# generators are mainly designed for iteration
julia> [i * j for (i, j) in g]
3×3 Matrix{Int64}:
  4   5   6
  8  10  12
 12  15  18

Quand le résultat d'une compréhension est immédiatement utilisé pour un traitement ultérieur, un générateur peut être économe en mémoire, ce qui évite de stocker un grand tableau intermédiaire.

Un générateur utilisé comme argument de fonction n'a pas besoin de parenthèses supplémentaires.

# inefficient
julia> v = [x^2 for x in 1:1e6];
julia> sum(v)
3.333338333335e17
# better - use a generator
julia> sum(x^2 for x in 1:1e6)
3.3333383333312755e17

La syntaxe d'un générateur est identique à celle d'une compréhension, à l'exception des crochets qui l'entourent.

Les générateurs peuvent aussi être pratiques dans les constructeurs de dictionnaires.

julia> Dict(x => x^2 for x in 1:5)
Dict{Int64, Int64} with 5 entries:
  5 => 25
  4 => 16
  2 => 4
  3 => 9
  1 => 1

Instructions

Tu travailles dans une boutique de mode en ligne. Tu as l'idée d'une fonctionnalité du site pour suggérer des tenues à l'utilisateur. On s'intéresse aux tenues possibles, à leurs prix, et à la façon d'éliminer les associations qui ne vont pas ensemble.

Note

S'il existe plusieurs façons de résoudre les problèmes qui suivent, tous peuvent être résolus avec une compréhension.

1. Crée un vêtement

Implémente clothingitem() pour qu'elle prenne deux Tuple, l'un de categories et l'autre des qualities correspondantes. La fonction doit renvoyer un Dict dont les categories sont les clés et les qualities les valeurs.

julia> categories = ("item_name", "price", "color", "base_color");

julia> qualities = ("Descriptive Name", 99.00, "Ochre Red", "red");

julia> clothingitem(categories, qualities)
Dict{String, Any} with 4 entries:
  "price"      => 99.0
  "item_name"  => "Descriptive Name"
  "base_color" => "red"
  "color"      => "Ochre Red"

Ta fonction doit pouvoir gérer n'importe quel nombre de categories.

2. Suggère des combinaisons

Implémente get_combinations() pour qu'elle prenne un Tuple de hauts et un Tuple de bas. La fonction doit renvoyer le cartesian product des tuples sous forme de tableau à deux dimensions (c'est-à-dire une Matrix). Chaque entrée est une combinaison (top, bottom) sous la forme d'un Tuple. Les hauts varient le long des lignes, les bas varient le long des colonnes.

julia> tops = (
        Dict("item_name" => "Dress shirt"),
        Dict("item_name" => "Casual shirt")
        );

julia> bottoms = (
        Dict("item_name" => "Jeans"),
        Dict("item_name" => "Dress trousers")
       );

julia> get_combinations(tops, bottoms)
2×2 Matrix{Tuple{Dict{String, String}, Dict{String, String}}}:
 (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Jeans"))   (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Dress trousers"))
 (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Jeans"))  (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Dress trousers"))

3. Additionne les prix des tenues

Chaque pièce de vêtement possède un champ price qui lui est associé, il peut donc être utile de pouvoir comparer le prix total des tenues. Implémente get_prices(), qui prend un tableau de combinaisons de vêtements. La fonction doit renvoyer un tableau de forme identique, avec les prix des tenues à leurs positions respectives.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combomatrix = get_combinations(tops, bottoms);

julia> get_prices(combomatrix)
2×2 Matrix{Int}::
 65  110
 50   95

julia> filteredmatrix = filter_clashing(combomatrix)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))

julia> get_prices(filteredmatrix)
1-element Vector{Int}:
 50

4. Élimine les tenues qui ne vont pas ensemble

Chaque pièce de vêtement possède un champ base_color. Utilise ce champ pour supprimer toutes les combinaisons où le haut et le bas ont la même couleur de base. Implémente filter_clashing() pour qu'elle prenne un tableau de combinaisons de vêtements. Renvoie un tableau à une dimension (c'est-à-dire un Vector) contenant les combinaisons correspondantes.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combos = get_combinations(tops, bottoms);

julia> filter_clashing(combos)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Julia Exercism

Prêt à commencer Suggestions de la boutique ?

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