Enum est un module très utile qui fournit un ensemble d'algorithmes pour manipuler les énumérables. Il permet de trier, de filtrer, de regrouper, de compter, de chercher, de trouver les valeurs minimales et maximales, et bien plus encore.
De manière générale, un énumérable est une donnée que l'on peut parcourir, c'est-à-dire une collection. En Elixir, un énumérable est n'importe quel type de données qui implémente le protocole Enumerable. Les plus courants sont les listes et les maps.
De nombreuses fonctions Enum acceptent une fonction en argument.
Enum.all?([1, 2, 3, 4, 5], fn x -> x > 3 end)
# => false
Les fonctions Enum les plus courantes sont map et reduce.
map/2Enum.map/2 permet de remplacer chaque élément d'un énumérable par un autre élément. Le deuxième argument de Enum.map/2 est une fonction qui accepte l'élément d'origine et renvoie son remplacement.
reduce/3Enum.reduce/3 permet de réduire tout l'énumérable à une seule valeur. Pour cela, on utilise une variable spéciale appelée l'accumulateur. L'accumulateur transporte l'état intermédiaire de la réduction entre les itérations.
Le deuxième argument de Enum.reduce/3 est la valeur initiale de l'accumulateur. Le troisième argument est une fonction qui accepte un élément et un accumulateur, et renvoie la nouvelle valeur de l'accumulateur.
Quand on utilise des maps avec les fonctions Enum, la map est automatiquement convertie en une liste de deux tuples {key, value}.
Pour la retransformer en map, utilise Enum.into/2. Enum.into/2 est une fonction qui transforme un énumérable en un collectable : toute structure de données qui implémente le protocole Collectable. On peut le voir comme l'opposé de Enum.reduce/3.
Enum propose également Enum.into/3. Enum.into/3 est une variante de Enum.into/2 qui accepte une fonction de transformation à appliquer pendant que l'énumérable est transformé en collectable.
Au lieu d'utiliser Enum.into/3 ou Enum.map/2 suivi de Enum.into/2 pour appliquer une transformation (un mapping) à une map, on peut aussi utiliser la fonction dédiée Map.new/2. Elle fonctionne exactement comme Enum.into/3 : elle accepte un énumérable et une fonction de transformation, mais renvoie toujours une nouvelle map au lieu de laisser choisir le collectable.
Tu gères une boutique de mode en ligne. Ta grande vente annuelle approche, alors tu dois faire l'inventaire de ton stock pour t'assurer que tout est prêt.
Chaque article de l'inventaire est représenté par un dictionnaire, et l'inventaire entier est un tableau de ces dictionnaires.
%{
name: "White Shirt",
price: 40,
quantity_by_size: %{s: 3, m: 7, l: 8, xl: 4}
}
Implémente la fonction sort_by_price/1. Elle doit prendre l'inventaire et le renvoyer trié par prix des articles, par ordre croissant.
BoutiqueInventory.sort_by_price([
%{price: 65, name: "Maxi Brown Dress", quantity_by_size: %{}},
%{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
%{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
%{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}}
])
# => [
# %{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}},
# %{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
# %{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
# %{price: 65, name: "Maxi Brown Dress", price: 65, quantity_by_size: %{}}
# ]
Après avoir trié ton inventaire par prix, tu as remarqué que tu avais dû faire une erreur au moment de faire l'inventaire et oublier de renseigner le prix de quelques articles.
Implémente la fonction with_missing_price/1. Elle doit prendre l'inventaire et renvoyer un tableau des articles qui n'ont pas de prix.
BoutiqueInventory.with_missing_price([
%{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
%{price: nil, name: "Denim Pants", quantity_by_size: %{}},
%{price: nil, name: "Denim Skirt", quantity_by_size: %{}},
%{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
])
# => [
# %{price: nil, name: "Denim Pants", quantity_by_size: %{}},
# %{price: nil, name: "Denim Skirt", quantity_by_size: %{}}
# ]
Tu as remarqué que le nom de certains articles contient un mot que tu ne veux plus utiliser. Tu dois maintenant mettre à jour tous les noms d'articles qui contiennent ce mot.
Implémente la fonction update_names/3. Elle doit prendre l'inventaire, l'ancien mot que tu veux supprimer, et un nouveau mot que tu veux utiliser à la place. Elle doit renvoyer un tableau des articles avec les noms mis à jour.
BoutiqueInventory.update_names(
[
%{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
%{price: 70, name: "Denim Pants", quantity_by_size: %{}},
%{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
%{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
],
"T-shirt",
"Tee"
)
# => [
# %{price: 40, name: "Black Tee", quantity_by_size: %{}},
# %{price: 70, name: "Denim Pants", quantity_by_size: %{}},
# %{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
# %{price: 40, name: "Orange Tee", quantity_by_size: %{}}
# ]
Certains articles se vendaient particulièrement bien, alors tu en as commandé davantage, dans toutes les tailles.
Implémente la fonction increase_quantity/2. Elle doit prendre un seul article et un nombre n, et renvoyer cet article avec la quantité de chaque taille augmentée de n.
BoutiqueInventory.increase_quantity(
%{
name: "Polka Dot Skirt",
price: 68,
quantity_by_size: %{s: 3, m: 5, l: 3, xl: 4}
},
6
)
# => %{
# name: "Polka Dot Skirt",
# price: 68,
# quantity_by_size: %{l: 9, m: 11, s: 9, xl: 10}
# }
Pour savoir de combien de place tu as besoin dans ton stockage, tu dois savoir combien tu as de pièces de chaque article au total.
Implémente la fonction total_quantity/1. Elle doit prendre un seul article et renvoyer combien tu as de pièces au total, toutes tailles confondues.
BoutiqueInventory.total_quantity(%{
name: "Red Shirt",
price: 62,
quantity_by_size: %{s: 3, m: 6, l: 5, xl: 2}
})
# => 16
Inscris-toi sur Exercism pour apprendre et maîtriser Elixir avec 58 concepts168 exercices, et un vrai mentorat humain, le tout gratuitement.