Favicon
NSI Première

Correction - Données en tables

Indexation des données

Indexation sous forme de tableau de tableaux


import csv

def index_tableau(nomDeFichier):
    tab = []
    with open(nomDeFichier,'r',encoding='utf-8') as f:
        lecteur = csv.reader(f,delimiter=',')
        for row in lecteur:
            tab.append(row)
    return tab	

tab = index_tableau("countries.csv") # construction du tableau de tableaux
print(tab)                           # affichage tableau entier
print(tab[2])                        # 3ème ligne
print(tab[51])                       # 52ème ligne
			

Indexation sous forme de tableau de dictionnaires


import csv

def index_dico(nomDeFichier):
    tab=[]
    with open(nomDeFichier,'r',encoding='utf-8') as f:
        lecteur=csv.DictReader(f,delimiter=',')
        for row in lecteur:
            tab.append(dict(row))
    return tab

tab = index_dico("countries.csv") # construction du tableau de dictionnaires
print(tab)                           # affichage tableau entier
print(tab[2])                        # 3ème ligne
print(tab[51])                       # 52ème ligne
			

Recherche dans une table

Dans la suite, le code de la fonction d'indexation ne sera plus indiqué. Le tableau de dictionnaires porte le nom de tabDico.

Recherche simple

Premières recherches


def recherche(donnees,clef_rech,val_rech,clef_aff):
	'''
	donnees : tableau de dictionnaires contenant les données
	clef_rech : clef à laquelle appartient la valeur recherchée  
	val_rech : valeur recherchée
	clef_aff : clef de la valeur que l'on veut afficher 
	'''
	for element in donnees:
		if element[clef_rech] == val_rech:
			return element[clef_aff]		
	
# Monnaie utilisée au Botswana :
print(recherche(tabDico, "name", "Botswana", "currency_name"))

# Superficie de Hong-Kong :
print(recherche(tabDico, "name", "Hong Kong", "area"))

# Code ISO de la Micronésie :
print(recherche(tabDico, "name", "Micronesia", "iso"))

# Pays dont le code ISO est CR :
print(recherche(tabDico, "iso", "CR", "name"))
			

Gestion des doublons


# Pays dont la monnaie est l'euro :
print(recherche(tabDico, "currency_name", "Euro", "name"))
print(recherche(tabDico, "currency_code", "EUR", "name")) # autre possibilité
			

→ n'affiche que le premier pays dans le tableau dont la monnaie est l'euro ( Andorre ), et pas tous les autres...

Solution :


def recherche2(donnees, clef_rech, eletrech, clef_aff):
    return [r[clef_aff] for r in donnees if r[clef_rech] == eletrech]
    
print(recherche2(tabDico,'currency_code','EUR','name'))	
			

Recherche par critères


def rechercheA(donnees):
    return [p['name'] for p in donnees if int(p['population'])<100000 and p['continent'] == 'EU']

def rechercheB(donnees):
    return [p['name'] for p in donnees if float(p['area'])>9000000 and p['currency_code'] == 'USD']

print(rechercheA(tabDico))
print(rechercheB(tabDico))

# noms des pays dont la population est de moins de 1000 habitants, ou dont la superficie est supérieure à 10000000
[p['name'] for p in tabDico if int(p['population'])<1000 or float(p['area'])>10000000)]		
			

Tests de cohérence


def coherenceB(donnees):
    for pays in donnees:
        if pays['continent'] not in ['AF', 'AS', 'EU', 'NA', 'OC', 'SA']:
            print('Incohérence pour', pays)
            
print(coherenceB(tabDico))		
			

Tri d'une table

Exemples de tri


tabDico.sort()

>>> TypeError: '<' not supported between instances of 'dict' and 'dict'
			

Le critère de tri


def cle_population(p):
   return p['population']

tabDico = index_dico("countries.csv")
tabDico.sort(key = cle_population)
print(tabDico[0], tabDico[1], tabDico[2])
			

→ le tableau de dictionnaires n'est pas classé par ordre de valeur de population, car cette donnée est en fait une chaîne de caractères (str) dans les dictionnaires : le tri ne se fait donc pas selon l'ordre numérique, mais selon l'ordre lexicographique, c'est à dire celui des caractères, et pas celui des nombres.
Selon cet ordre, on aura alors par exemple: "232" > "12345689", car le caractère "2" suit le caractère "1" dans l'ordre lexicographique; selon l'ordre numérique, on aurait bien entendu : 232 < 12345689...

Il faut donc convertir les données de population en nombre entier :


def cle_population(p):
   return int(p['population']) # et là, ça fonctionne !

tabDico = index_dico("countries.csv")
tabDico.sort(key = cle_population)
print(tabDico[0], tabDico[1], tabDico[2])
			

Pour afficher les noms des pays de la zone Euro par ordre de population croissante :


def cle_population(p):
   return int(p['population'])

tabDico = index_dico("countries.csv")
tabEuro = [p for p in tabDico if p['currency_code'] == "EUR"] # tableau des dictionnaires des pays de la zone Euro
tabEuro.sort(key = cle_population)
print(tabEuro)
			

Pour afficher les noms des pays de la zone Euro par ordre de superficie croissante :


def cle_superficie(p):
   return float(p['area']) # la superficie est un nombre flottant

tabDico = index_dico("countries.csv")
tabEuro = [p for p in tabDico if p['currency_code'] == "EUR"] # tableau des dictionnaires des pays de la zone Euro
tabEuro.sort(key = cle_superficie)
print(tabEuro)
			

Fusion de deux tables

Construction d'une nouvelle table

Fusion "à la main"


|     acteur      |  film_id  |    titre    |  anSortie  |  duree  | vo |  genres  |  recette  |
|-----------------|-----------|-------------|------------|---------|----|----------|-----------|
|   Hugo Haas     |    212    |Tête de thon |    1998    |   120   | fr |  comédie |  137000   |
| Bill Waterson   |    212    |Tête de thon |    1998    |   120   | fr |  comédie |  137000   |
|Xavier Le Noëllec|    131    | Paddle Life |    2020    |   105   |bzh | aventure |  452000   | 			
			

Fonction de fusion


def fusion(table1, cle1, table2, cle2):
    fusion = []
    for element1 in table1:                                   # pour chaque dictionnaire dans la première table,
        for element2 in table2:                               # pour chaque dictionnaire dans la deuxième table,
            if element1[cle1] == element2[cle2]:              # si les deux valeurs correspondant à cle1 et cle2 sont les mêmes dans les deux tables,
                element_fusion = element1                     # alors on a trouvé la colonne de données communes aux deux tables.
                for clef in element2:                         # on parcourt alors les colonnes de la deuxième table, 
                    element_fusion[clef] = element2[clef]     # et on stocke chacune de ces colonnes dans le dictionnaire de fusion.
                fusion.append(element_fusion)                 # on ajoute le dictionnaire à la table fusionnée.
    return fusion
    
countries = index_dico("countries.csv")
cities = index_dico("cities.csv")
f = fusion(countries, "capital", cities, "id")
print(f[0])

>>> {'iso': 'AD', 'name': 'Andorra', 'area': '468.0', 'population': '84000', 'continent': 'EU', 'currency_code': 'EUR', 'currency_name': 'Euro', 'capital': '6', 'id': '6', 'nameCity': 'Andorra la Vella', 'latitude': '42.50779', 'longitude': '1.52109', 'country': 'AD', 'populationCity': '20430'}
			

→ la donnée des colonnes communes aux deux tables ("id" et "capital" ) se retrouve deux fois dans la table fusionnée : il ne faut donc stocker cette information qu'une seule fois :


def fusion(table1, cle1, table2, cle2):
    fusion = []
    for element1 in table1:                                   
        for element2 in table2:                              
            if element1[cle1] == element2[cle2]:              
                element_fusion = element1                     
                for clef in element2:                         
                    if clef != cle2:                          # si la colonne n'est pas celle correspondant à cle2,
                        element_fusion[clef] = element2[clef] # alors seulement on stocke cette colonne dans le dictionnaire fusion.
                fusion.append(element_fusion)                 
    return fusion
    
countries = index_dico("countries.csv")
cities = index_dico("cities.csv")
f = fusion(countries, "capital", cities, "id")
print(f[0])

>>> {'iso': 'AD', 'name': 'Andorra', 'area': '468.0', 'population': '84000', 'continent': 'EU', 'currency_code': 'EUR', 'currency_name': 'Euro', 'capital': '6', 'nameCity': 'Andorra la Vella', 'latitude': '42.50779', 'longitude': '1.52109', 'country': 'AD', 'populationCity': '20430'}
			

→ la colonne "id" a bien été supprimée.

Recherche dans une table de fusion

Les fonctions de recherche peuvent être alors utilisées, comme pour une table non fusionnée :


#Afficher toutes les capitales dans lesquelles on peut dépenser des Euros :
print([p['nameCity'] for p in f if p['currency_code'] == 'EUR'])

# Afficher le nom des pays dont la capitale a moins de 100 000 habitants :
print([p['name'] for p in f if int(p['populationCity']) < 100000])

# Afficher le nom des pays dont la capitale est située entre les deux tropiques (de latitudes -23.436° et +23.436°)
print([p['name'] for p in f if -23.436 < float(p['latitude']) < 23.436])