Résumé en français : Une pizzeria récompense ses meilleurs clients en offrant une pizza gratuite s’ils ont fait au moins 5 achats d’un montant au moins égal à 20 EUR. Cependant, ce système est susceptible d’être modifié dans le futur. On vous demande de créer une fonction qui à partir du nombre d’achats minimum, du montant minimum et d’un dictionnaire contenant les données sur vos clients, va renvoyer la liste de ceux qui auront une pizza gratuite.
# Système 1 : Pour avoir une pizza gratuite, il faut avoir au moins 5 achats d'un montant minimum de 20 EUR.
min_achats = 5
min_prix = 20
conso = {
'John Doe' : [22, 30, 11, 17, 15, 52, 27, 12], # Montants des achats
'Jane Doe' : [5, 17, 30, 33, 40, 22, 26, 10, 11, 45]
}
>> free(conso, min_achats, min_prix)
['Jane Doe'] # Elle seule aura une pizza gratuite
# Système 2 : Pour avoir une pizza gratuite, il faut avoir au moins 2 achats d'un montant minimum de 50 EUR.
min_achats = 2
min_prix = 50
conso = {
'Joey Bonzo' : [22, 67, 53, 29], # Montants des achats
'Jennifer Bonzo' : [51, 19]
}
>> free(conso, min_achats, min_prix)
['Joey Bonzo']
Version classique
Pour chaque consommateur, on va compter le nombre d’achats dont le montant est ≥ au montant minimum imposé. Si ce nombre est ≥ au minimum d’achats, la personne aura une pizza gratuite.
On peut imaginer une première boucle pour parcourir les consommateurs, une seconde pour parcourir les achats et enfin un test pour savoir si cette personne doit avoir une pizza.
Comment :
– récupérer les différents consommateurs ?
– récupérer leurs achats ?
Partons de cet exemple :
conso = {
'John Doe' : [22, 30, 11, 17, 15, 52, 27, 12],
'Jane Doe' : [5, 17, 30, 33, 40, 22, 26, 10, 11, 45]
}
Python
>> conso.keys() # Autre solution plus bas
dict_keys(['John Doe', 'Jane Doe'])
>> list(conso.keys())
['John Doe', 'Jane Doe']
JavaScript
>> Object.keys(conso)
['John Doe', 'Jane Doe']
APL
conso ← ('John Doe' 22 30 11 17 15 52 27 12)
('Jane Doe' 5 17 30 33 40 22 26 10 11 45)
1↑¨conso ⍝ Premier élément de chaque
┌──────────┬──────────┐
│┌────────┐│┌────────┐│
││John Doe│││Jane Doe││
│└────────┘│└────────┘│
└──────────┴──────────┘
Et pour récupérer les achats d’un consommateur :
Python & JavaScript
>> conso['John Doe']
[22, 30, 11, 17, 15, 52, 27, 12]
APL
1↓¨ conso ⍝ Achats des différents clients
┌───────────────────────┬────────────────────────────┐
│22 30 11 17 15 52 27 12│5 17 30 33 40 22 26 10 11 45│
└───────────────────────┴────────────────────────────┘
python
On peut également parcourir à la fois les clés et les valeurs. Voici un exemple qui calcule le montant total des achats des consommateurs :
>> conso = {
'John Doe' : [22, 30, 11, 17, 15, 52, 27, 12],
'Jane Doe' : [5, 17, 30, 33, 40, 22, 26, 10, 11, 45]
}
>> for (p, achats) in conso.items():
print('Total pour {} : {}'.format(p, sum(achats)))
Total pour John Doe : 186
Total pour Jane Doe : 239
Version finale à tester ici qui reprend notre première approche :
def free(conso, min_achats, min_prix):
gagnants = [ ] # Personnes qui auront une pizza gratuite
for p in conso.keys(): # On parcourt les consommateurs
achats = conso[p] # Récupération des achats
total = 0 # Nb d'achats ≥ montant min
for m in achats: # On parcourt les achats
if m >= min_prix : # Si montant ≥ montant min
total += 1 # On ajoute +1
if total >= min_achats: # Suffisamment d'achats ?
gagnants.append(p) # Il aura une pizza gratuite
return gagnants # Retour de la liste des gagnants
>> free(conso, min_achats, min_prix) # Avec l'exemple 1
['Jane Doe']
javascript
Vous pouvez tester cette version ici :
const free = (conso, min_achats, min_prix) => {
gagnants = [ ];
for (p of Object.keys(conso))
{
achats = conso[p];
total = 0 ;
for (m of achats)
{
if (m >= min_prix) total +=1
}
if (total >= min_achats) gagnants.push(p)
}
return gagnants}
>> free(conso, min_achats, min_prix) // Avec l'exemple 1
['Jane Doe']
Version plus moderne
Nous devons filtrer les consommateurs suivant un double critère : Nombre de pizzas achetés et ayant un prix ≥ montant minimum. Rappelons brièvement comment on peut filtrer en Python, JavaScript et APL, par exemple en cherchant quels étudiants ont des notes ≥ 10 :
notes = [5, 12, 11, 9, 3, 17, 18, 6]
Python
>> [v for v in notes if v >= 10]
[12, 11, 17, 18]
JavaScript
>> notes.filter(v => v >= 10)
[12, 11, 17, 18]
APL
notes ← 5 12 11 9 3 17 18 6
(notes ≥ 10) / notes ⍝ Version 1
12 11 17 18
(10 ≤ notes) ⊆ notes ⍝ Version 2
┌─────┬─────┐
│12 11│17 18│
└─────┴─────┘
10 (≤ ⊆ ⊢) notes ⍝ Version "train"
┌─────┬─────┐
│12 11│17 18│
└─────┴─────┘
∊ (10 ≤ notes) ⊆ notes
12 11 17 18
10 (∊ < ⊆ ⊢) notes
12 11 17 18
Et pour compter le nombre d’étudiants reçus (c’est-à-dire avec une note ≥ 10 :
notes = [5, 12, 11, 9, 3, 17, 18, 6]
Python
>> len([v for v in notes if v >= 10]) # Taille du tableau
4
>> sum([v >= 10 for v in notes]) # Somme de True ou False
4
>> sum(v >= 10 for v in notes) # Parenthèses inutiles
4
JavaScript
>> notes.filter(v => v >= 10).length
4
>> notes.reduce((a, v) => a + (v >= 10), 0)
4
APL
notes ← 5 12 11 9 3 17 18 6
notes +.≥ 10 ⍝ Somme des éléments ≥ 10
4
On obtient ainsi ces 2 versions plus modernes pour JavaScript et Python :
javascript
const free = (conso, min_achats, min_prix) =>
Object.keys(conso) // Liste de consommateurs
.filter(p => // Pour chaque personne p
conso[p] // On filtre ses achats
.filter(m => m >= min_prix) // en gardant ceux ≥ min_prix
.length // On compte le nombre d'achats ok
>= min_achats // On garde la personne si ≥ min_achats
)
python
def free(conso, min_achats, min_prix):
return [ \
p for p in conso.keys() \ # on garde le consommateur si...
if sum(m >= min_prix for m in conso[p]) \ # Nb achats ≥ min_prix
>= min_achats \ # ...dépasse min_achats
]
APL
On veut sélectionner ( / ) les noms des consommateurs, pour cela on va utiliser un vecteur logique (booléen) :
1↑¨conso ⍝ Noms des consommateurs
┌──────────┬──────────┐
│┌────────┐│┌────────┐│
││John Doe│││Jane Doe││
│└────────┘│└────────┘│
└──────────┴──────────┘
1 0 / 1↑¨conso ⍝ je veux le 1er et pas le 2e nom
┌──────────┐
│┌────────┐│
││John Doe││
│└────────┘│
└──────────┘
Créons le vecteur logique :
conso ← ('John Doe' 22 30 11 17 15 52 27 12)
('Jane Doe' 5 17 30 33 40 22 26 10 11 45)
(1↓⊢)¨ conso ⍝ Achats des consommateurs
┌───────────────────────┬────────────────────────────┐
│22 30 11 17 15 52 27 12│5 17 30 33 40 22 26 10 11 45│
└───────────────────────┴────────────────────────────┘
(20 +.≤ 1↓⊢)¨ conso ⍝ Nombre d'achats ≥ 20
4 6
20 (⊣ +.≤ 1↓⊢)¨ conso ⍝ Version plus générale
4 6
5 ≤ 20 (⊣ +.≤ 1↓⊢)¨ conso ⍝ Ce nb d'achats est-il ≥ 5 ?
0 1
(5 ≤ 20 (⊣ +.≤ 1↓⊢)¨ conso) / 1↑¨conso ⍝ Pizza gratuite pour
┌──────────┐
│┌────────┐│
││Jane Doe││
│└────────┘│
└──────────┘
Ce qui amène à cette version finale en APL à tester ici :
free ← {(⍺[1] ≤ (⍺[2] +.≤ 1↓⊢)¨⍵) / 1↑¨⍵}
5 20 free conso
┌──────────┐
│┌────────┐│
││Jane Doe││
│└────────┘│
└──────────┘
2 50 free ('Joey Bonzo' 22 67 53 29) ('Jennifer Bonzo' 51 19)
┌────────────┐
│┌──────────┐│
││Joey Bonzo││
│└──────────┘│
└────────────┘