Aller au contenu

Résultat :

Correction - Données en table


1. Manipulation de fichiers CSV

  • On peut représenter un enregistrement par un dictionnaire.
  • Une virgule (CSV : Comma Separated Values - Valeurs séparées par une virgule). Néanmoins, le format CSV autorise d'autres séparateurs.
  • La table étant une liste de dictionnaires, on obtient donc le premier élément de la liste, c'est à dire un dictionnaire, donc une ligne de la table.

2. Opérations sur les tables

  • Pour sélectionner des colonnes selon un critère donné, on va utiliser la fonction projection.
def projection(table, liste_attributs):
  return [{clé:ligne[clé] for clé in ligne if clé in liste_attributs} for ligne in table]
  • La fonction select ici va sélectionner les lignes dont une des valeurs vaut 19. On obtient donc :
[{'Prénom': 'Chandler', 'Math': '19', 'Anglais': '15', 'NSI': '17'},
 {'Prénom': 'Ross', 'Math': '14', 'Anglais': '19', 'NSI': '13'}]
  • Il y a deux (2) noms qui sont communs aux tables : on aura donc deux (2) lignes. De plus, la table U rajoute ses deux (2) colonnes (Âge, Mail) aux quatre de la table T : on aura donc 6 (six) colonnes.

3. Déterminer des fonctions basiques

  • Puisqu'il s'agit de compter le nombre de lignes, donc d'enregistrements, on peut donc utiliser la fonction len pour obtenir la longueur de la liste de dictionnaires.
def cardinalite(table):
    return len(table)
  • La liste des attributs d'une table correspond aux clés du premier dictionnaire (en supposant que la table est cohérente) :
def attributs(table):
    if len(table) == 0:
        return []
    return list(table[0].keys())

4. Reconnaître une fonction

def mystère(t, cs):
  t_p = []
  for l in t :
    nvlle_l = {}
    for c in l:
      if c in cs:
        nvelle_l[c] = l[c]
    t_p.append(nvlle_l)
  return t_p

Cette fonction réalise une projection : elle crée une nouvelle table ne contenant que les colonnes (attributs) spécifiés dans la liste cs.

  • t est la table d'origine (liste de dictionnaires)
  • cs est la liste des colonnes à conserver
  • Pour chaque ligne l de la table, on crée un nouveau dictionnaire nvlle_l ne contenant que les clés présentes dans cs
  • On retourne la nouvelle table t_p

Remarque : Il y a une erreur dans le code original (nvelle_l au lieu de nvlle_l). La version corrigée serait :

def projection(table, colonnes):
    table_projetee = []
    for ligne in table:
        nouvelle_ligne = {}
        for colonne in ligne:
            if colonne in colonnes:
                nouvelle_ligne[colonne] = ligne[colonne]
        table_projetee.append(nouvelle_ligne)
    return table_projetee

5. Tester la cohérence d'une table

  • Fonction coherence qui teste si chaque ligne a le même ensemble d'attributs :
def coherence(table):
    """
    Teste si chaque ligne de la table a le même ensemble d'attributs
    :param table: (list) une liste de dictionnaires
    :return: (bool) True si la table est cohérente, False sinon
    """
    if len(table) == 0:
        return True

    attributs_reference = set(table[0].keys())

    for ligne in table:
        if set(ligne.keys()) != attributs_reference:
            return False

    return True
  • Fonction doublons qui vérifie si un attribut apparaît deux fois avec la même valeur :
def doublons(table, attribut):
    """
    Vérifie si un attribut apparaît deux fois avec la même valeur
    :param table: (list) une liste de dictionnaires
    :param attribut: (str) le nom de l'attribut à vérifier
    :return: (bool) True s'il y a des doublons, False sinon
    """
    valeurs_vues = []

    for ligne in table:
        valeur = ligne[attribut]
        if valeur in valeurs_vues:
            return True
        valeurs_vues.append(valeur)

    return False

6. Lier tableur, fichier CSV et liste de dictionnaires

PlanningTwitch = [
    {'NomStream': 'AntoineDaniel', 'Genre': 'M', 'Jeu': 'Fall_Guys', 'Numéro': '1'},
    {'NomStream': 'MV', 'Genre': 'M', 'Jeu': 'Isaac', 'Numéro': '2'},
    {'NomStream': 'AngleDroit', 'Genre': 'F', 'Jeu': 'Fall_Guys', 'Numéro': '3'},
    {'NomStream': 'BagheraJones', 'Genre': 'F', 'Jeu': 'Fall_Guys', 'Numéro': '4'}
]
  • La première ligne de la feuille de calcul contient les en-têtes (attributs) : NomStream | Genre | Jeu | Numéro

  • Pour obtenir le fichier CSV correspondant :

    vers_csv('PlanningTwitch', ['NomStream', 'Genre', 'Jeu', 'Numéro'])
    

  • La deuxième ligne du fichier CSV : AntoineDaniel;M;Fall_Guys;1

  • La cellule C8 de la feuille correspondante : la table n'a que 5 lignes (1 en-tête + 4 données), donc C8 est vide.

  • Pour obtenir la valeur d'une cellule (par exemple C2, le jeu d'AntoineDaniel) :

    PlanningTwitch[0]['Jeu']  # 'Fall_Guys'
    

  • Pour modifier le jeu de MV :

    PlanningTwitch[1]['Jeu'] = 'Worms'
    


7. Ajouter une ligne ou une colonne

  • Pour obtenir la liste de dictionnaires depuis le fichier CSV :

    Groupe1 = import_csv('Groupe1')
    

  • Pour ajouter Rachel :

    Groupe1.append({'Prénom': 'Rachel', 'Math': '17', 'Anglais': '19', 'NSI': '18'})
    

  • Fonction pour ajouter une colonne moyenne :

from copy import deepcopy

def ajouter_moyenne(table):
    """
    Ajoute une colonne 'Moyenne' à chaque ligne de la table
    :param table: (list) une liste de dictionnaires avec des notes
    :return: (list) une nouvelle table avec la colonne Moyenne
    """
    nouvelle_table = deepcopy(table)

    for ligne in nouvelle_table:
        math = int(ligne['Math'])
        anglais = int(ligne['Anglais'])
        nsi = int(ligne['NSI'])
        moyenne = (math + anglais + nsi) / 3
        ligne['Moyenne'] = '{:.1f}'.format(moyenne)

    return nouvelle_table
  • Pour ajouter une ligne contenant les moyennes par matière :
from copy import deepcopy

def ajouter_ligne_moyennes(table):
    """
    Ajoute une ligne contenant les moyennes par matière
    :param table: (list) une liste de dictionnaires avec des notes
    :return: (list) une nouvelle table avec la ligne des moyennes
    """
    nouvelle_table = deepcopy(table)

    nb_eleves = len(nouvelle_table)
    total_math = 0
    total_anglais = 0
    total_nsi = 0

    for ligne in nouvelle_table:
        total_math = total_math + int(ligne['Math'])
        total_anglais = total_anglais + int(ligne['Anglais'])
        total_nsi = total_nsi + int(ligne['NSI'])

    ligne_moyennes = {
        'Prénom': 'Moyenne',
        'Math': '{:.1f}'.format(total_math / nb_eleves),
        'Anglais': '{:.1f}'.format(total_anglais / nb_eleves),
        'NSI': '{:.1f}'.format(total_nsi / nb_eleves)
    }

    nouvelle_table.append(ligne_moyennes)
    return nouvelle_table

8. Sélectionner, trier, joindre

On définit les tables :

Hero = [
    {'NumHero': '0', 'NomHero': 'Sangoku', 'VilleHero': 'Kyoto'},
    {'NumHero': '1', 'NomHero': 'Naruto', 'VilleHero': 'Konoha'},
    {'NumHero': '2', 'NomHero': 'Luffy', 'VilleHero': 'Fuchsia'},
    {'NumHero': '3', 'NomHero': 'Ryo Saeba', 'VilleHero': 'Tokyo'},
    {'NumHero': '4', 'NomHero': 'Saitama', 'VilleHero': 'Ville Z'},
    {'NumHero': '5', 'NomHero': 'Onizuka', 'VilleHero': 'Tokyo'}
]

Armes = [
    {'NumHero': '0', 'NomHero': 'Sangoku', 'Arme': 'Ki'},
    {'NumHero': '1', 'NomHero': 'Naruto', 'Arme': 'Chakra'},
    {'NumHero': '2', 'NomHero': 'Luffy', 'Arme': 'Corps'},
    {'NumHero': '3', 'NomHero': 'Ryo Saeba', 'Arme': 'Magnum'},
    {'NumHero': '4', 'NomHero': 'Saitama', 'Arme': 'Poing'},
    {'NumHero': '5', 'NomHero': 'Onizuka', 'Arme': 'Tout est une arme'}
]
  • HeroTokyo : héros dont la ville est Tokyo
HeroTokyo = select(Hero, "ligne['VilleHero'] == 'Tokyo'")
# Résultat :
# [{'NumHero': '3', 'NomHero': 'Ryo Saeba', 'VilleHero': 'Tokyo'},
#  {'NumHero': '5', 'NomHero': 'Onizuka', 'VilleHero': 'Tokyo'}]
  • HeroAlpha : héros triés par ordre alphabétique du nom
HeroAlpha = tri(Hero, 'NomHero')
# Résultat :
# [{'NumHero': '2', 'NomHero': 'Luffy', 'VilleHero': 'Fuchsia'},
#  {'NumHero': '1', 'NomHero': 'Naruto', 'VilleHero': 'Konoha'},
#  {'NumHero': '5', 'NomHero': 'Onizuka', 'VilleHero': 'Tokyo'},
#  {'NumHero': '3', 'NomHero': 'Ryo Saeba', 'VilleHero': 'Tokyo'},
#  {'NumHero': '4', 'NomHero': 'Saitama', 'VilleHero': 'Ville Z'},
#  {'NumHero': '0', 'NomHero': 'Sangoku', 'VilleHero': 'Kyoto'}]
  • HeroComplet : nom, ville et arme des héros (fusion puis projection)
HeroFusion = fusion(Hero, Armes, 'NumHero')
HeroComplet = projection(HeroFusion, ['NomHero', 'VilleHero', 'Arme'])
# Résultat :
# [{'NomHero': 'Sangoku', 'VilleHero': 'Kyoto', 'Arme': 'Ki'},
#  {'NomHero': 'Naruto', 'VilleHero': 'Konoha', 'Arme': 'Chakra'},
#  {'NomHero': 'Luffy', 'VilleHero': 'Fuchsia', 'Arme': 'Corps'},
#  {'NomHero': 'Ryo Saeba', 'VilleHero': 'Tokyo', 'Arme': 'Magnum'},
#  {'NomHero': 'Saitama', 'VilleHero': 'Ville Z', 'Arme': 'Poing'},
#  {'NomHero': 'Onizuka', 'VilleHero': 'Tokyo', 'Arme': 'Tout est une arme'}]
  • HeroVille : numéro et ville des héros
HeroVille = projection(Hero, ['NumHero', 'VilleHero'])
# Résultat :
# [{'NumHero': '0', 'VilleHero': 'Kyoto'},
#  {'NumHero': '1', 'VilleHero': 'Konoha'},
#  {'NumHero': '2', 'VilleHero': 'Fuchsia'},
#  {'NumHero': '3', 'VilleHero': 'Tokyo'},
#  {'NumHero': '4', 'VilleHero': 'Ville Z'},
#  {'NumHero': '5', 'VilleHero': 'Tokyo'}]
  • HeroImpair : nom et ville des héros ne venant pas de Tokyo et dont le numéro est impair
HeroImpair = select(Hero, "ligne['VilleHero'] != 'Tokyo' and int(ligne['NumHero']) % 2 == 1")
HeroImpair = projection(HeroImpair, ['NomHero', 'VilleHero'])
# Résultat :
# [{'NomHero': 'Naruto', 'VilleHero': 'Konoha'}]

Source : Florian Mathieu - Licence CC BY NC SA