Aller au contenu

Exercices d'entraînement
Jointures

Ces exercices doivent être utilisés pour vous entraîner à programmer. Ils sont généralement accompagnés d'aide et de leur solution pour vous permettre de progresser.

Avant de vous précipiter sur ces solutions dès la première difficulté, n'oubliez pas les conseils suivants :

  • Avez-vous bien fait un schéma au brouillon pour visualiser le problème posé ?
  • Avez-vous essayé de rédiger un algorithme en français, avec vos propres mots, avant de vous lancer dans la programmation sur machine ?
  • Avez-vous utilisé des affichages intermédiaires, des print(), pour visualiser au fur et à mesure le contenu des variables ?
  • Avez-vous testé le programme avec les propositions de tests donnés dans l'exercice ?
  • Avez-vous testé le programme avec de nouveaux tests, différents de ceux proposés ?

Attention

  • Ne pas oublier de sauvegarder les fichiers dans le répertoire [NSI_Tables_Donnees].
  • Ne pas oublier d'importer le module fonctions_csv.
  • Ne pas oublier d'importer les fichiers CSV en tableau de dictionnaires pour pouvoir utiliser les fonctions...

ProgC02.71

On utilise dans cet exercice deux tables, à télécharger et à placer dans le répertoire de travail :

  • la table clients.csv.
    Nommez cette table importée : clients.

  • la table commandes.csv.
    Nommez cette table importée : commandes.

La table clients

id_client nom prenom
1 Bagou Albert
2 Charabia Barnabé
3 Blabla Casimir
4 Paulitik Zoé
5 Escro Virgil
6 Manteux Rémi

La table commandes

id_commande id_client descriptif
1 2 bouilloire
2 3 Livre Apprende Python
3 2 Livre Apprendre HTML
4 4 Livre Apprendre CSS
5 6 couverture
6 4 VTT
7 4 smartphone
8 1 cahiers
9 2 Livre Le réseau internet
10 3 Livre Les systèmes d’exploitation
11 1 Livre Algorithmique

Le numéro d'identification du client id_client est un attribut commun à ces deux tables.

  1. En utilisant la fonction jointure() du module fonctions.csv, réalisez la jointure entre les tables clients et commande. Cette jointure sera stockée dans la variable clients_commandes.

    Une solution
    1
    2
    3
    4
    5
    6
    7
    8
    from fonctions_csv import *
    
    
    ##----- Programme principal -----##
    clients = importe_csv('clients')
    commandes = importe_csv('commandes')
    
    clients_commandes = jointure(clients, commandes, 'id_client')
    
  2. Ordonnez la table clients_commandes suivant l'ordre croissant des noms des clients et, pour un même client, suivant l'ordre croissant des id_commande.

    Contenu de clients_commandes à obtenir
    {'id_client': 1, 'nom': 'Bagou', 'prenom': 'Albert', 'id_commande': 8, 'descriptif': 'cahiers'}
    {'id_client': 1, 'nom': 'Bagou', 'prenom': 'Albert', 'id_commande': 11, 'descriptif': 'Livre Algorithmique '}
    {'id_client': 2, 'nom': 'Charabia', 'prenom': 'Barnabé', 'id_commande': 1, 'descriptif': 'bouilloire'}
    {'id_client': 2, 'nom': 'Charabia', 'prenom': 'Barnabé', 'id_commande': 3, 'descriptif': 'Livre Apprendre HTML '}
    {'id_client': 2, 'nom': 'Charabia', 'prenom': 'Barnabé', 'id_commande': 9, 'descriptif': 'Livre Le réseau internet '}
    {'id_client': 3, 'nom': 'Blabla', 'prenom': 'Casimir', 'id_commande': 2, 'descriptif': 'Livre Apprende Python '}
    {'id_client': 3, 'nom': 'Blabla', 'prenom': 'Casimir', 'id_commande': 10, 'descriptif': 'Livre Les systèmes d’exploitation'}
    {'id_client': 4, 'nom': 'Paulitik', 'prenom': 'Zoé', 'id_commande': 4, 'descriptif': 'Livre Apprendre CSS '}
    {'id_client': 4, 'nom': 'Paulitik', 'prenom': 'Zoé', 'id_commande': 6, 'descriptif': 'VTT'}
    {'id_client': 4, 'nom': 'Paulitik', 'prenom': 'Zoé', 'id_commande': 7, 'descriptif': 'smartphone'}
    {'id_client': 6, 'nom': 'Manteux', 'prenom': 'Rémi', 'id_commande': 5, 'descriptif': 'couverture'}
    
    Une solution

    Ne pas oublier de transformer les valeurs de id_client et id_commande en entiers sous peine de voir la commande numéro '11' passer devant la commande numéro '8' pour le premier client... (car le caractère '1' est alphabétiquement devant le caractère '8' !).

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from fonctions_csv import *
    
    def NumClient(dico):
        return dico["id_client"]
    
    def NumCommande(dico):
        return dico["id_commande"]
    
    
    ##----- Programme principal -----##
    clients = importe_csv('clients.csv')
    commandes = importe_csv('commandes.csv')
    
    clients_commandes = jointure(clients, commandes, 'id_client')
    
    attributs_entiers(clients_commandes, ['id_client', 'id_commande'])
    clients_commandes.sort(key=NumCommande)
    clients_commandes.sort(key=NumClient)
    

  3. Sauvegardez la table ainsi générée dans un fichier CSV nommé clients_commandes.csv puis affichez cette table à l'aide d'un tableur.

    La table à obtenir

    id_client nom prenom id_commande descriptif
    1 Bagou Albert 8 cahiers
    1 Bagou Albert 11 Livre Algorithmique
    2 Charabia Barnabé 1 bouilloire
    2 Charabia Barnabé 3 Livre Apprendre HTML
    2 Charabia Barnabé 9 Livre Le réseau internet
    3 Blabla Casimir 2 Livre Apprende Python
    3 Blabla Casimir 10 Livre Les systèmes d’exploitation
    4 Paulitik Zoé 4 Livre Apprendre CSS
    4 Paulitik Zoé 6 VTT
    4 Paulitik Zoé 7 smartphone
    6 Manteux Rémi 5 couverture

    Une réponse
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from fonctions_csv import *
    
    def NumClient(dico):
        return dico["id_client"]
    
    def NumCommande(dico):
        return dico["id_commande"]
    
    
    ##----- Programme principal -----##
    clients = importe_csv('clients.csv')
    commandes = importe_csv('commandes.csv')
    
    clients_commandes = jointure(clients, commandes, 'id_client')
    
    attributs_entiers(clients_commandes, ['id_client', 'id_commande'])
    clients_commandes.sort(key=NumCommande)
    clients_commandes.sort(key=NumClient)
    
    exporte_csv(clients_commandes, "clients_commandes.csv", ['id_client', 'nom', 'prenom', 'id_commande', 'descriptif'])
    

ProgC02.72

On utilise dans cet exercice deux tables, à télécharger et à placer dans le répertoire de travail :

  • la table personnes.csv.
    Nommez cette table importée : table_personnes.

  • la table cours.csv.
    Nommez cette table importée : table_cours.

La table table_personnes

id_personne nom prenom annee_naissance
1 Labrosse Adam 2000
2 Gemlamorte Adèle 1985
3 Auboisdormant Abel 2001
4 Etpan Ahmed 1975
5 Térieur Alain 1999
6 Térieur Alex 1976
7 Proviste Alain 2000
8 Verse Alain 1970
9 Ception Alex 2001
10 Ainé Ali 1975
11 Gator Ali 2001
12 Bistraux Alonzo 2001
13 Patamob Alphonse 1970
14 Ficulté Andy 1980
15 Rectdustade Andy 2000
16 Verserre Annie 2001
17 Boréal Aurore 1985
18 Nor Paul 1985
19 Dejeu Bernadette 2001
20 Dajeun Bruno 1984
21 Hiple Candice 2000

La table table_cours

La colonne id_enseignant fait référence à la colonne id_personne de la table personnes.

Par exemple, on peut lire que le cours sur la théorie des graphes est assuré par madame Gemlamorte Adèle.

id_cours id_enseignant intitule
1 2 théorie des graphes
2 4 programmation objet
3 6 programmation fonctionnelle
4 8 théorie des automates
5 10 base de données relationnelle
6 13 réseaux
7 14 langage python
8 17 html et css
9 18 javascript
10 20 java
11 2 algorithmique
12 4 tests logiciels
13 6 intelligence artificielle
14 8 UML
15 10 XML
16 13 scheme
17 14 merise
18 14 webgl
19 Unix

Écrivez un programme Python qui construise la table cours_complets qui est la fusion des deux tables précédentes.

  • Les champs (attributs) de cette table seront 'id_personne', 'nom', 'prenom', 'id_cours', 'intitule'.
    Cette table met donc en face de chaque personne les cours qu'elle assure.

  • Chaque personne devra apparaître dans la table même si elle n'assure pas de cours ('id_cours' et 'intitule' seront dans ce cas associées à la chaîne vide : '').

  • Une personne assurant plusieurs cours apparaît sur autant de lignes...

  • Un cours qui n'est assuré par personne devra aussi apparaître (avec '' pour valeur associée aux clefs identifiant l'enseignant).

  • La table devra être triée selon le nom des personnes (ordre croissant).
    Et pour une même personne, les lignes seront triées selon le nom des cours (ordre croissant).

  • La table créée sera exportée dans un fichier intitulé cours_complets.csv.

La table à obtenir

id_personne nom prenom id_cours intitule
19 Unix
10 Ainé Ali 15 XML
10 Ainé Ali 5 base de données relationnelle
3 Auboisdormant Abel
12 Bistraux Alonzo
17 Boréal Aurore 8 html et css
9 Ception Alex
20 Dajeun Bruno 10 java
19 Dejeu Bernadette
4 Etpan Ahmed 2 programmation objet
4 Etpan Ahmed 12 tests logiciels
14 Ficulté Andy 7 langage python
14 Ficulté Andy 17 merise
14 Ficulté Andy 18 webgl
11 Gator Ali
2 Gemlamorte Adèle 11 algorithmique
2 Gemlamorte Adèle 1 théorie des graphes
21 Hiple Candice
1 Labrosse Adam
18 Nor Paul 9 javascript
13 Patamob Alphonse 6 réseaux
13 Patamob Alphonse 16 scheme
7 Proviste Alain
15 Rectdustade Andy
5 Térieur Alain
6 Térieur Alex 13 intelligence artificielle
6 Térieur Alex 3 programmation fonctionnelle
8 Verse Alain 14 UML
8 Verse Alain 4 théorie des automates
16 Verserre Annie

Une solution
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from fonctions_csv import *

def Nom(dico):
    return dico['nom']

def Discipline(dico):
    return dico['intitule']

##----- Programme principal -----##
table_personnes = importe_csv('personnes.csv')
table_cours = importe_csv('cours.csv')

# Tout d'abord, on joint les deux tables
cours_complets = jointure(table_personnes, table_cours, 'id_personne', 'id_enseignant')
cours_complets = projection(cours_complets, ['id_personne', 'nom', 'prenom', 'id_cours', 'intitule'])


# Puis une boucle pour ajouter les personnes ne donnant pas de cours
for personne in table_personnes:
    present = False
    for dico in cours_complets:
        if personne['id_personne'] == dico['id_personne']:
            present = True
    if not present:
        cours_complets.append({'id_personne': personne['id_personne'],
                    'nom': personne['nom'],
                    'prenom': personne['prenom'],
                    'id_cours': '',
                    'intitule': ''}
                    )


# Dernière boucle pour ajouter les cours n'ayant pas d'enseignant
for crs in table_cours:
    present = False
    for dico in cours_complets:
        if crs['id_cours'] == dico['id_cours']:
            present = True
    if not present:
        cours_complets.append({'id_personne': '',
                    'nom': '',
                    'prenom': '',
                    'id_cours': crs['id_cours'],
                    'intitule': crs['intitule']}
                    )


# Tri et exportation
cours_complets.sort(key=Discipline)
cours_complets.sort(key=Nom)

exporte_csv(cours_complets, 'cours_complets.csv', ['id_personne', 'nom', 'prenom', 'id_cours', 'intitule'])
Remarque sur le tri

L'ordre des lettres est l'ordre ASCII :
les majuscules sont situées avant les minuscules. Cela explique pourquoi le cours 'XML' de Ali Ainé est placé avant le cours 'base de données relationnelle'.
Pour résoudre ce problème, il suffit de trier suivant les chaînes préalablement toutes passées en minuscule, ce qui se fait facilement avec la méthode .lower() en remplaçant les deux fonctions de tris par:

1
2
3
4
5
def Nom(dico):
    return dico['nom'].lower()

def Discipline(dico):
    return dico['intitule'].lower()
Fichier csv obtenu

ProgC02.73

On utilise ici trois tables, à télécharger et à placer dans le répertoire de travail :

  • la table personnalites.csv.
    Nommez cette table importée : table_personnalites.

  • la table joue.csv.
    Nommez cette table importée : table_joue.

  • la table films.csv. Nommez cette table importée : table_films.

La table table_personnalites

id_personne nom prenom
1 Brasseur Claude
2 Boon Dany
3 Goldblum Jeff
4 Reno Jean
5 Balasko Josiane
6 Olivares Gerardo
7 Emmerich Roland
8 Kidmann Nicole
9 Kubrick Stanley
10 Cruise Tom
11 McQuarrie Christopher
12 Spielberg Steven
13 Ford Harrison
14 Abrams JJ
15 Merad Kad
16 Rich Claude
17 Tavernier Bertrand
18 Robert Yves
19 Berri Claude
20 Aghion Gabriel
21 Darmon Gérard
22 Laroque Michèle

La table table_joue

id_acteur fait référence à l'id_personne de la table_personnalites. id_film fait référence à l'id_film de la table_films.

Ainsi, on sait que Nicole Kidmann (id_personne = 8) joue le rôle d'Alice (id_role = 1) dans "Eyes Wide Shut" (id_film = 1).

id_role id_acteur id_film role
1 8 1 Alice
2 10 1 Bill
3 10 2 Ethan Hunt
4 10 3 John Anderton
5 13 6 Indiana Jones
6 13 7 Han Solo
7 2 8 Antoine Bailleul
8 15 8 Philippe Abrams
9 16 9 Duc Clovis de Crassac
10 1 10 Daniel
11 2 11 Seb
12 21 11 Loïc
13 22 11 Marie Hagutte

La table table_films

id_realisateur fait référence à id_personne de la table_personnalites.

id_film id_realisateur titre genre annee
1 9 Eyes Wide Shut drame 1999
2 11 Mission impossible 5 action 2015
3 12 Minority Report SF 2002
4 12 Les dents de la mer épouvante 1975
5 12 E.T. l'extraterrestre SF 1982
6 12 Les aventuriers de l'Arche perdue aventure 1981
7 14 Star Wars - Le Réveil de la Force SF 2015
8 2 Bienvenue chez les Ch'tis comédie 2008
9 17 La fille de D'Artagnan cape et épée 1994
10 18 "Un éléphant ça trompe énormément" comédie 1976
11 20 Pédale dure comédie 2004

Écrivez un programme Python qui construit la table roles qui est la fusion des trois tables précédentes.

  • Les champs (attributs) de cette table seront le nom et le prénom de l'acteur, le film dans lequel il joue, l'année de sortie du film, son rôle dans le film et le nom et le prénom du réalisateur du film.

  • La table sera triée par ordre croissant des noms des acteurs et, pour un même acteur, par ordre décroissant des titres de film.

  • La table créée sera exportée dans un fichier intitulé roles_acteurs.csv.

La table à obtenir

nom_acteur prenom_acteur titre annee role nom_real prenom_real
Boon Dany Pédale dure 2004 Seb Aghion Gabriel
Boon Dany Bienvenue chez les Ch'tis 2008 Antoine Bailleul Boon Dany
Brasseur Claude "Un éléphant, ça trompe énormément" 1976 Daniel Robert Yves
Cruise Tom Mission impossible 5 2015 Ethan Hunt McQuarrie Christopher
Cruise Tom Minority Report 2002 John Anderton Spielberg Steven
Cruise Tom Eyes Wide Shut 1999 Bill Kubrick Stanley
Darmon Gérard Pédale dure 2004 Loïc Aghion Gabriel
Ford Harrison Star Wars - Le Réveil de la Force 2015 Han Solo Abrams JJ
Ford Harrison Les aventuriers de l'Arche perdue 1981 Indiana Jones Spielberg Steven
Kidmann Nicole Eyes Wide Shut 1999 Alice Kubrick Stanley
Laroque Michèle Pédale dure 2004 Marie Hagutte Aghion Gabriel
Merad Kad Bienvenue chez les Ch'tis 2008 Philippe Abrams Boon Dany
Rich Claude La fille de D'Artagnan 1994 Duc Clovis de Crassac Tavernier Bertrand

Une indication

Travaillez d'abord sur la jointure entre table_personnalités et table_joue afin d'obtenir une table ne contenant que le nom et le prénom des acteurs, leur rôle et le numéro du film dans lequel l'acteur joue.
Puis effectez de même entre table_personnalités et table_films.

Une autre indication

Il peut être utile de créer une fonction qui renomme les attributs une fois les jointures effectuées.

Une solution
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from fonctions_csv import *

def renommer_attributs(table, tab_attributs1, tab_attributs2):
    assert len(tab_attributs1) == len(tab_attributs2), "Erreur : les tableaux n'ont pas le même nombre d'éléments."
    for dico in table:
        for i in range(len(tab_attributs1)):
            dico[tab_attributs2[i]] = dico[tab_attributs1[i]]
            del dico[tab_attributs1[i]]

def Acteurs(dico):
    return dico['nomActeur']

def Titres(dico):
    return dico['titre']

##----- Programme principal -----##
table_personnalites = importe_csv('personnalites.csv')
table_joue = importe_csv('joue.csv')
table_films = importe_csv('films.csv')

# Jointure et projection de table_personnalites et table_joue
casting = jointure(table_personnalites, table_joue, 'id_personne', 'id_acteur')
renommer_attributs(casting, ['nom', 'prenom'], ['nomActeur', 'prenomActeur'])
casting = projection(casting, ['nomActeur', 'prenomActeur', 'id_film', 'role'])


# Jointure et projection de table_personnalites et table_films
realisation = jointure(table_personnalites, table_films, 'id_personne', 'id_realisateur')
renommer_attributs(realisation, ['nom', 'prenom'], ['nomReal', 'prenomReal'])
realisation = projection(realisation, ['nomReal', 'prenomReal', 'id_film', 'titre', 'annee'])


# Jointure et projection des deux tables précédentes
roles = jointure(casting, realisation, 'id_film')
roles = projection(roles, ['nomActeur', 'prenomActeur', 'titre', 'annee', 'role', 'nomReal', 'prenomReal'])


# Tri et exportation
roles.sort(key=Titres, reverse=True)
roles.sort(key=Acteurs)

exporte_csv(roles, 'rolesActeurs', ['nomActeur', 'prenomActeur', 'titre', 'annee', 'role', 'nomReal', 'prenomReal'])