<string>

Table des matières

Mission 7 - Dictionnaires

Mission 7 : Dictionnaires

Mission 7 : Dictionnaires

Introduction

Le but de cette mission est de développer un outil qui permet un utilisateur de chercher répétitivement dans un fichier de texte: pour des mots donnés, l'outil va imprimer les phrases dans lesquelles tous les mots donnés sont présents. Pour assurer que l'outil ne prend pas trop de temps pour déterminer ces phrases, on va construire un index des mots présents dans les phrases des documents. On utilisera les dictionnaires pour stocker l'index.

Objectifs

Objectifs individuels

A l’issue de ce problème, chacun d’entre vous sera en mesure d’exploiter les notions suivantes :
  • dictionnaires
  • fichiers

Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes du syllabus en ligne :

Questionnaire de démarrage

Questions à choix multiple

Les questions à choix multiples de cette mission sont également accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session7_QCM


        
        

Question 1

Considérez le code suivant:

codes = {"Bruxelles" : [1000,1020,1030], "Louvain-la-Neuve" : [1348], "Wavre": [1300,1301]}

Les morceaux de code ci-dessous sont executés chacun après ce code. Décrivez ce qui se passe pour chacun des cas.

  • On exécute :
print(codes["Bruxelles"])
 
 

  • On exécute :
print(codes["Mons"])
 
 

  • On exécute :
print(codes[1000])
 
 

  • On exécute :
print(codes.get("Mons",[]))
 
 

  • On exécute:
codes["Liege"] = [4000]
print(codes)
 
 

  • On exécute:
codes["Bruxelles"].append(1040)
print(codes)
 
 

  • On exécute:
codes.get("Bruxelles",[]).append(1050)
print(codes)
 
 

  • On exécute:
codes.get("Arlon",[]).append(8362)
print(codes)
 
 

  • On exécute:
if "Bruxelles" in codes:
  print("Found!")
else:
  print("Not found!")
 

  • On exécute:
if 1000 in codes:
  print("Found!")
else:
  print("Not found!")
 

  • On exécute:
for x in codes:
  print(x)
 
 
 

  • On exécute:
for x in codes:
  print(codes[x])
 
 
 

  • On exécute:
for x in codes.items():
  print(x)
 
 

  • On exécute:
for x, y in codes.items():
  y = y + [2000]
print(codes)
 
 

  • On exécute:
for x, y in codes.items():
  y.append(2000)
print(codes)
 
 

  • On exécute:
for x, y in codes.items():
  x = x + "*"
print(codes)
 
 

Question 2

Considérez le code suivant:

def mot_ligne(ligne):
    d = {}
    for mot in ligne:
        d[mot] = 1
    return d

Quelle est la taille du dictionnaire résultant des appels suivants ? Pourquoi ?

  • mot_ligne(["the","world","goes","round"])
  • mot_ligne(["the","world","and","the","galaxy"])
  • mot_ligne(["run","run","run"])

Question 3

Écrivez une fonction avec la spécification suivante:

def create_index ( list_of_words ):
    """ crée un index pour une liste de chaînes de caractères.
        L'index se compose d'un dictionnaire dans lequel pour chaque
        chaîne de caractères dans list_of_strings on retrouve une
        liste des positions où l'on retrouve cette chaîne de
        caractères.

        Par exemple, pour la liste

          ["the","galaxy","and","the","universe","are","the","same"]

        Le résultat est

          {"the":[0,3,6],"galaxy":[1],"and":[2],"universe":[4], \
           "are":[5],"same":[7]}

    Args:
        list_of_words: une liste de chaînes de caractères
    Retourne:
        un dictionnaire avec pour chaque mot dans la liste,
        une liste des positions de cette chaîne de caractères
        dans la liste
    """


        
        

Question 4

Étant donnée:

  • une matrice representée en utilisant des listes imbriquées
  • une matrice representée en utilisant un dictionnaire, où les zéros ne sont pas stockées.

Par exemple,

l = [ [ 0, 2, 4 ], [ 4, 1, 0 ] ]
d = { (0,1): 2, (0,2): 4, (1,0): 4, (1,1): 1 }

Écrivez une fonction equal(l,d) qui détermine si d contient les même valeurs pour chaque élément de l. (Nous permettons que d soit plus large que l.)


        
        

Question 5

Étant donné une structure de données comme la suivante:

System Message: ERROR/3 (<string>, line 420)

Content block expected for the "code-block" directive; none found.

.. code-block:: python

l = [{"City": "Bruxelles", "Country": "Belgium"},
{"City": "Berlin", "Country": "Germany"}, {"City": "Paris", "Country": "France"}]

Écrivez une fonction get_country(l,name) qui, pour le nom d'une ville name et une structure de données l du format illustré dans l'exemple, retourne le nom du pays dans lequel la ville est localisée. La fonction retourne None si la ville n'est pas dans l.


        
        

Mission 7

Mission 7

Le but de cette mission est de contribuer à un outil qui permet un utilisateur de chercher répétitivement dans un fichier de texte.

Il faut implementer les fonctions suivantes dans un fichier search.py et vérifier que ces fonctions sont correctes:

  • La fonction readfile(filename) avec la spécification suivante:

    def readfile(filename):
        """ Crée une liste des lignes contenues dans un fichier dont le nom est ``filename``
    
        Args:
            filename: le nom d'un fichier de texte
        Retourne:
            une liste dans laquelle chaque ligne du fichier filename est un élément.
            Si filename n'existe pas, la fonction retourne une liste vide.
        """
    
  • La fonction get_words(line) avec la spécification suivante:

    def get_words(line):
        """ Pour une chaîne de caractères donnée, retourne une liste des mots dans
            la chaîne en minuscules et dans l'ordre d'apparence dans le texte. La
            ponctuation et les caractères non-alphabétiques doivent être ignorés et
            retirés des mots.
    
            Par exemple :
                - Pour la chaîne de caractères :
                    "Turmoil has engulfed the Galactic Republic. The taxation of
                    trade routes to outlying star systems is in dispute."
                  Le résultat est :
                    ["turmoil", "has", "engulfed", "the", "galactic", "republic",
                    "the", "taxation", "of", "trade", "routes", "to", "outlying",
                    "star", "systems", "is", "in", "dispute" ]
                - Pour la chaîne de caractères :
                    "These aren't the droids you're looking for."
                  Le résultat est :
                    ['these', 'arent', 'the', 'droids', 'youre', 'looking', 'for']
    
            Un caractère est considéré comme une ponctuation ou un
            caractère non-alphabétique si ce n'est pas une lettre, selon la
            fonction string.isalpha().
    
        Args:
            line: une chaîne de caractères.
        Retourne:
            une liste des mots dans la chaîne, en minuscules, et sans ponctuation.
        """
    

    Ici, vous pouvez utiliser la méthode string.isalpha(); un exemple de l'utilisation de cette méthode se trouve ci-dessous:

    text = "a.b"
    r = ""
    for c in text:
      if c.isalpha():
        r += c
    print(r)  # "ab"
    
  • La fonction create_index(filename) avec la spécification suivante:

    def create_index(filename):
        """ crée un index pour le fichier avec nom ``filename``. L'index se compose
            d'un dictionnaire dans lequel pour chaque mot du fichier ``filename``
            on retrouve une liste des indices des lignes du fichier qui contiennent
            ce mot.
    
            Par exemple, pour un fichier avec le contenu suivant:
    
              While the Congress of the Republic endlessly debates
              this alarming chain of events, the Supreme Chancellor has
              secretly dispatched two Jedi Knights.
    
            Une partie de l'index, representé comme dictionnaire, est:
    
    
              {"while": [0], "the": [0,1], "congress": [0], \
               "of": [0,1], "republic": [0], ... , "jedi": [2], ...}
    
        Args:
            filename: une chaîne de caractères
        Retourne:
            un dictionnaire avec pour chaque mot du fichier (en minuscules)
            la liste des indices des lignes qui contiennent ce mot.
        """
    

    Cette fonction doit utiliser les fonctions get_words et readfile.

  • La fonction get_lines(words,index) avec la spécification suivante:

    def get_lines(words, index):
       """ Détermine les lignes qui contiennent tous les mots indexes dans ``words``,
           selon l'index ``index``.
    
           Par exemple, pour l'index suivant:
    
             index = {"while": [0], "the": [0,1], "congress": [0], \
                      "of": [0,1], "republic": [0], ... , "jedi": [2], ...}
    
           La fonction retourne
             get_lines(["the"], index) -> [0, 1]
             get_lines(["jedi"], index) -> [2]
             get_lines(["the", "of"], index) -> [0, 1]
             get_lines(["while", "the"], index) -> [0]
             get_lines(["congress", "jedi"], index) -> []
             get_lines(["while", "the", "congress"], index) -> [0]
    
       Args:
           words: une liste de mots, en minuscules
           index: un dictionnaire contenant pour mots (en minuscules) des listes de nombres entiers
       Retourne:
           une liste des nombres des lignes contenant tous les mots indiqués
       """
    

    Commencez par faire cette fonction uniquement pour les listes avec un mot; dans ce cas, l'outil marche au moins quand l'utilisateur spécifie un seul mot. Essayez de modifier cette fonction pour les listes plus longues ensuite.

    Plusieurs approches sont possible pour calculer le résultat de get_lines() pour des listes de mots plus longues. Une possibilité est de traverser la liste associé au premier mot, et de vérifier si on trouve dans ces lignes aussi les autre mots, en utilisant l'index de chaque mot.

De nouveau, les fonctions ci-dessus doivent être mises en oeuvre dans un fichier search.py.

L'outil est implementé dans un fichier utility.py, qui importe le fichier search.py. Voici le code de utility.py, que vous pouvez soumettre sans le modifier:

import search

filename = input("Spécifiez le nom de fichier: ")
index = search.create_index(filename)
while True:
  words = input("Spécifiez les mots a rechercher, en utilisant des espaces entre les mots: ")
  lines = search.get_lines(words.strip().split(), index)
  print("Les mots se retrouvent dans ces lignes:")
  for line in lines:
    print(line)

Autrement dit, après avoir demandé le nom d'un fichier, dans une boucle, l'interface demande à l'utilisateur de donner une liste de mots; chaque fois, l'outil cherche les lignes dans lesquelles les mots spécifiés sont présents, et imprime ces lignes. Votre tâche principale est de vous assurer que l'outil fonctionne correctement, en mettant en oeuvre les fonctions dans le fichier search.py.

Pour vous aider, vous trouverez un exemple de texte episodeIV_dialogues.txt.

Créez les fonctions dans l'ordre spécifié. Si vous n'arrivez pas à terminer toutes les fonctions, soumettez les fonctions que vous avez réussi à terminer.

Pour assurer que l'outil marche correctement, vous devez ajouter des tests pour vérifier que les fonctions sont correctes; par exemple, les tests pour la fonction get_words doivent être mis dans une fonction test_get_words. Puisque vous devez tester une fonction qui lit un fichier, créez des petits fichiers pour tester cette fonction; il faut soumettre ces fichiers de texte aussi.

Les tests doivent être mis dans un fichier test.py qui importe search.py. Un petit exemple du contenu du fichier test.py est:

import search


def test_get_words():
  assert search.get_words("Turmoil has engulfed the Galactic Republic.") == ["turmoil", "has", "engulfed", "the", "galactic", "republic"], "Petit exemple donné"

test_get_words()

Si vous le souhaitez, vous pouvez étendre l'outil même, par exemple, pour montrer les lignes au lieu des nombres des lignes. Dans ce cas vous pouvez modifier le code du fichier utility.py. Indiquez ceci dans le commentaire de utility.py.

Remise de votre solution

Pour cette mission, vous devez soumettre:

  • un fichier search.py ;
  • un fichier utility.py (éventuellement non modifié en comparaison avec le code donné ci-dessus);
  • un fichier test.py avec les tests (qui étendent l'exemple donné ci-dessus);
  • 2 petits fichiers de texte que vous utilisez dans vos tests
  • un fichier README

        
        
Questions complémentaires

Questions complémentaires

Lors de la dernière session du club de duel, les sabliers comptant les points de chaque maison ont été détruits même un reparo n'a rien pu faire et la célébration de la Coupe des Quatre Maisons arrive à grands pas!

Heureusement, Rusard, qui ne fait pas confiance à la magie, a gardé les comptes de tous les accomplissements perpétrés par les étudiants. Il vous a fourni un dictionnaire associant chaque élève à sa maison et un parchemin avec tous leurs gains.

La liste des scores est donnée dans un fichier. Le contenu de ce fichier suit le format suivant :

  • Lignes: student_name points

Merci de retourner le nom de la maison gagnante, dans le cas d'un ex-aequo : retournez une liste des meilleures maisons.

S'il y a une erreur, levez une exception.

Implémentez la fonction winning_house(scroll) en Python.

Vous avez déjà la liste des étudiants triés par maison à votre disposition :

students = {'gryffindor': ['Harry', 'Hermione', 'Ron', 'Ginny', 'Fred', ' Georges', 'Neville'],
            'ravenclaw': ['Cho', 'Luna', 'Sybill', 'Marcus', 'Marietta', 'Terry', 'Penelope'],
            'hufflepuff': ['Pomona', 'Zacharias', 'Teddy', 'Cedric', 'Nymphadora', 'Newton', 'Justin'],
            'slytherin': ['Malfoy', 'Severus', 'Dolores', 'Horace', 'Blaise', 'Pansy', 'Bellatrix']}


        
        

Anonymous a été épaté par votre travail et a décidé de vous faire confiance pour l'analyse de toutes les données qu'ils ont intercepté.

Avec l'aide des deux fonctions que vous avez déjà créées, vous allez transformer chaque ligne de données en un pattern et extraire le nombre d’occurrences présentes dans le fichier.

Créez une fonction collect(data) pour lire le fichier, extraire les patterns et les enregistrer dans un dictionnaire avec leurs occurrences.

S'il y a une erreur, levez une exception.

Rappel:

  • extract(code): donne la nature de chaque élément d'une string.
  • treatment(code): transforme une suite d'éléments en un pattern.


        
        

Après la troisième guerre mondiale, la planète est laissée dans un état post-apocalyptique. Vous êtes l'un des seuls survivants et vous cherchez un peu de compagnie. Mais vous ne pouvez pas trop swiper sur Tinder vu que le réseau est mort..

Heureusement votre meilleur ami est avec vous... Votre ordinateur (oui, ça craint!) Avec son aide, aide vous allez pouvoir entrer en contact avec le reste du monde. Puisque vous avez un dictionnaire Morse enregistré sur votre machine (Matt Damon avait bien une table ASCII avec lui dans "Seul sur Mars" , donc c'est pas si absurde), vous allez l'utiliser pour traduire votre texte et l'émettre grâce à une vieille radio.

Notez que si vous devez essayer de traduire un caractère non-enregistré, vous devez lever une exception TypeError.

Implémentez la fonction translate(data) en Python.

Avec data comme chaine de caractère que vous voulez encoder en Morse et un dictionnaire morse utile pour faire les traductions.

morse = {
"A" : ".-",
"B" : "-...",
"C" : "-.-.",
"D" : "-..",
"E" : ".",
...
}


        
        

Votre tinder par radio a bien fonctionné et vous pouvez désormais discuter avec beaucoup de gens intéressants. Encore plus intéressant, une merveilleuse créature vient de vous contacter et est parvenue à vous envoyer une image à travers des points et des espaces (Dieu bénisse le code Morse).

Vous voulez vraiment lui parler ainsi qu'à vos autres futurs matchs mais vous venez de réaliser que vous n'avez jamais bien étudier les langues étrangères. Heureusement, vous avez des dictionnaires sur votre ordinateur (qui a apparemment téléchargé l'entierté d'internet). Vous devez simplement coder un traducteur!

Notez que si un mot que vous voulez traduire n'est pas dans le dictionnaire, vous devez laisser le mot dans son langage original.

Exemple:

"I'm fond of Dean" deviendrait en français avec le dictionnaire fr: "je suis amoureux de doyen" Notez qu'on ne s'attend pas à ce que vous donniez des traductions exactes mais bien une traduction mot par mot. De plus, les clés sont enregistrées en minuscules dans le dictionnaire.

Implémentez la fonction translate(data, lan) en Python.

Avec data comme la chaine de caractère que vous souhaiter traduire et les dictionnaires nommés selon lan utilisable pour faire les traductions dans le langage ciblé.


        
        

Vous et vos amis vous prêtez souvent de l'argent. Plutôt que d'utiliser une application spéciale pour se rappeler qui doit combien d'argent et à qui, vous décidez de faire votre propre programme python pour réaliser cette tâche.

Spécifiquement, vous aimeriez pouvoir:

  • dire qui doit combien d'argent à qui;
  • changer les comptes quand quelqu'un rembourse ou prête de l'argent à un autre;
  • ajouter une personne qui emprunte et/ou rembourse de l'argent;
  • calcule la somme de tout l'argent emprunté à ce moment précis.

Notez que de l'argent prêté à quelqu'un doit être emprunté. En d'autres termes, si Woody a prêté 3€ à Buzz, votre programme devrait dire que Buzz doit 3€ à Woody et que Woody doit -3€ à Buzz.

Pour faire cela, vous allez utiliser un dictionnaire de dictionnaires appelé borrowed_money, indexé par le nom des personnes (comme des strings). Le premier index sera le nom de "l'emprunteur"; le deuxième, celui du "prêteur".

Par exemple, si Woody a prêté 3€ à Buzz, votre dictionnaire devrait être comme suit:

borrowed_money[\"Buzz\"][\"Woody\"] == 3  # Lisez \"Buzz doit 3€ à Woody\"
borrowed_money[\"Woody\"][\"Buzz\"] == -3

Par conséquent, vous pouvez obtenir un dictionnaire qui contient tout l'argent que Buzz emprunte:

borrowed_money[\"Buzz\"] == {\"Woody\": 3, \"Hamm\": 60, \"Rex\": -5}

Faites une fonction give_money(borrowed_money, from_person, to_person, amount) qui sera appelée quand from_person donne amount € à to_person (soit parce que from_person prête de l'argent to_person, ou bien parce qu'il rembourse de l'argent qu'il a emprunté). Si une des deux personnes n'est pas déjà une clé dans le dictionnaire, elle doit y être ajoutée. Vous devez lever une ValueError dans le cas où quelqu'un essaye de se donner de l'argent à lui-même.

Faites une autre fonction total_money_borrowed(borrowed_money) qui retourne le montant total d'argent emprunté en ce moment (c'est-à-dire, la somme des montants positifs se trouvant dans le dictionnaire).

Note: vous devez lever une ValueError``*si l'un des arguments passé à ces fonctions est invalide (c'est-à-dire si les noms ne sont pas de strings, si* ``borrowed_money n'est pas un dictionnaire ou si le montant d'argent n'est pas un integer ou un float). Vous pouvez tester si une variable est du bon type des manières suivantes :

variable = 5
type(variable) == int  # retourne True
# OR
isinstance(variable, int)  # retourne True

Enfin, implémentez l'exemple où Mark prête 2 000 000 € à Bill et Steve, Serguei prête 5 000 000 € à Bill, Bill prête 6 000 000 € à Larry et enfin, Larry prête 5,5 € à Linus. Ensuite, Steve rembourse Mark. Utilisez la variable borrowed_money.