<?xml version="1.0" encoding="UTF-8"?>
<quiz>
<question type="category">
  <category>
    <text>$course$/QCM de NSI/Première/Tables de données</text>
  </category>
  <info format="html">
    <text><![CDATA[<p>Représentation tabulaire des données, descripteurs<br/>
(colonnes), enregistrements (lignes), opérations courantes<br/>
(recherche, tri, sélection, fusion, jointure simple), en<br/>
Python avec listes de dictionnaires ou listes de listes.</p>]]></text>
  </info>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q01 : Qu'est-ce qu'une table ?</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>En informatique, qu'appelle-t-on une <strong>table de données</strong> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les tables sont la structure la plus simple et la<br/>
plus répandue pour organiser des données : tableurs,<br/>
bases relationnelles, fichiers CSV, DataFrames pandas<br/>
reposent tous sur ce modèle.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un fichier texte dont les valeurs sont séparées par des virgules</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est la description du format<br/>
<strong>CSV</strong>, qui n'est qu'un moyen de stocker<br/>
une table dans un fichier. La table<br/>
elle-même est la structure abstraite<br/>
(lignes et colonnes), indépendante de son<br/>
format d'enregistrement.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un type primitif fondamental fourni nativement par Python</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : Python n'a pas de type natif "table".<br/>
On peut la simuler avec des listes ou<br/>
dictionnaires.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Un tableau de lignes (enregistrements) et de colonnes (descripteurs)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : c'est la définition standard,<br/>
identique à celle d'un tableur ou d'une table<br/>
de base de données. Chaque ligne décrit une<br/>
entité (élève, livre...), chaque colonne un<br/>
attribut (nom, âge...).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une fonction Python qui renvoie un dictionnaire</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : c'est éventuellement un moyen de<br/>
<strong>représenter</strong> une table, pas la définition<br/>
elle-même.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q02 : Vocabulaire</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Comment appelle-t-on une <strong>colonne</strong> dans une table<br/>
de données ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Vocabulaire à maîtriser : ligne = enregistrement<br/>
= entité ; colonne = descripteur = attribut =<br/>
champ. Selon le manuel, le mot peut varier.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une ligne</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : confusion ligne/colonne. Une ligne<br/>
décrit une entité.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une clé primaire</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une clé primaire est un <strong>descripteur particulier</strong> qui identifie de manière unique<br/>
chaque ligne. Toutes les colonnes ne sont pas<br/>
des clés primaires.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un enregistrement, c'est-à-dire une entité complète de la table</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un enregistrement est une <strong>ligne</strong>,<br/>
pas une colonne.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Un descripteur (ou attribut, ou champ)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la colonne décrit une propriété<br/>
commune à toutes les entités (par exemple<br/>
"nom", "age", "ville"). Les termes<br/>
"descripteur", "attribut", "champ" sont<br/>
synonymes selon le contexte.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q03 : Liste de dictionnaires</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Comment représente-t-on couramment une table en<br/>
Python (avec en-tête) ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Autres représentations possibles : liste de<br/>
tuples, liste de listes, dict de listes (« colonne<br/>
par colonne »). Le choix dépend de l'usage. Pour<br/>
le NSI Première, on utilise principalement la liste<br/>
de dictionnaires.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Comme une seule et longue chaîne de caractères unique</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : ce ne serait pas pratique pour<br/>
manipuler les données.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Comme une liste de dictionnaires, un par ligne</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : exemple<br/>
<code>[{"nom":"Alice","age":17}, {"nom":"Bob","age":16}]</code>.<br/>
C'est ce que renvoie <code>csv.DictReader</code> quand on<br/>
le convertit en liste. Très lisible<br/>
(<code>ligne["nom"]</code>).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Comme une fonction</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une fonction décrit un calcul, pas<br/>
des données.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Comme un entier</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un entier ne stocke aucune<br/>
structure.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q04 : Accéder à une cellule</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Soit<br/>
<pre><code>table = [
    {"nom": "Alice", "age": 17},
    {"nom": "Bob", "age": 16}
]</code></pre><br/>
Comment accéder à l'âge de Bob ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Schéma général : <code>table[indice_ligne][descripteur]</code>.<br/>
L'ordre des accès reflète la structure : d'abord<br/>
la liste, puis le dictionnaire.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>table[1]['age']</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : Bob est la deuxième ligne<br/>
(indice 1), et <code>'age'</code> est le descripteur. On<br/>
obtient <code>16</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>table['Bob']['age']</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>table</code> est une <strong>liste</strong>, pas un<br/>
dictionnaire indexé par nom. Cela lève<br/>
<code>TypeError</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>table[2]['age']</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : indice <strong>hors-borne</strong>. Avec deux<br/>
lignes, les indices valides sont 0 et 1, pas<br/>
2 (<code>IndexError</code>).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>table.age[1]</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : aucune méthode ni attribut <code>.age</code> sur<br/>
une liste (<code>AttributeError</code>).</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q05 : Parcourir une table</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour afficher tous les noms d'élèves d'une table<br/>
(liste de dictionnaires avec une clé <code>"nom"</code>), quel<br/>
code utilise-t-on ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Schéma classique de parcours d'une liste de<br/>
dictionnaires. À retenir.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>for ligne in table:
    print(ligne.nom)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un dictionnaire n'a pas d'attribut<br/>
<code>.nom</code>, cette écriture lève <code>AttributeError</code>.<br/>
La valeur d'une clé s'obtient avec des<br/>
crochets : <code>ligne["nom"]</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>for ligne in table:
    print(ligne["nom"])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la boucle parcourt chaque<br/>
dictionnaire, et on accède à la valeur de la<br/>
clé <code>"nom"</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>for nom in table:
    print(nom)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la variable <code>nom</code> recevrait chaque<br/>
<strong>dictionnaire</strong> entier, pas le nom seulement.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>for ligne in table:
    print(table["nom"])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : dans la boucle, c'est <code>ligne</code> qu'il<br/>
faut indexer. <code>table</code> est une liste, on ne<br/>
peut pas l'indexer par une chaîne : <code>TypeError</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q06 : Origine des tables</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>D'où peut provenir une table de données dans un<br/>
projet réel ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Une compétence clé du NSI : savoir lire des<br/>
données réelles (souvent en CSV ou JSON), les<br/>
transformer en table Python, puis les manipuler.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>D'un fichier CSV ou JSON, d'un tableur, d'une base, d'une API...</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : les tables sont partout en<br/>
informatique. Open Data (data.gouv.fr),<br/>
extracts SQL, exports Excel, scraping web...<br/>
autant de sources possibles.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Uniquement de données saisies à la main au clavier</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Trop restrictif : une table peut aussi provenir<br/>
d'un fichier, d'une base ou d'une API, sans aucune<br/>
saisie manuelle.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Uniquement d'un fichier CSV créé à la main</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Trop restrictif : il existe de nombreuses<br/>
autres sources.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Uniquement à partir d'une base de données relationnelle SQL</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Trop restrictif : SQL est une source<br/>
fréquente mais pas la seule.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q07 : Recherche par critère</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour trouver toutes les lignes où l'âge est<br/>
strictement supérieur à 16, quel code écrit-on ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Compréhension de liste : schéma Python élégant<br/>
pour filtrer, transformer et combiner. Très<br/>
utilisé sur les tables.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>for ligne in table:
    if ligne["age"] &gt; 16:
        print(ligne)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Cela <strong>affiche</strong> les lignes mais ne renvoie<br/>
pas une liste. Si la question est "trouver",<br/>
on attend une valeur de retour, pas un<br/>
affichage.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>[ligne for ligne in table if ligne["age"] &gt; 16]</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : compréhension de liste avec<br/>
condition. Forme idiomatique en Python pour<br/>
filtrer.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>table.find(age &gt; 16)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la méthode <code>.find()</code> n'existe pas<br/>
sur les listes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>table[ligne["age"] &gt; 16]</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : syntaxe invalide. <code>ligne</code> n'est pas<br/>
défini hors d'une boucle.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q08 : Construire depuis CSV</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Quel est le moyen le plus simple de construire une<br/>
table (liste de dictionnaires) à partir d'un fichier<br/>
CSV avec en-tête ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Idiome standard. Penser à fermer le fichier<br/>
proprement avec un <code>with</code>, ou utiliser cette<br/>
écriture compacte si le fichier est petit.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Lire le fichier ligne par ligne et coder à la main le découpage</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : possible mais fastidieux et fragile<br/>
(séparateur, guillemets, en-tête). Le module<br/>
<code>csv</code> fait ce découpage pour nous.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>csv.load('data.csv')</code> (cette fonction existe-t-elle ?)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : cette fonction n'existe pas dans le<br/>
module <code>csv</code> (<code>AttributeError</code>).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>list(csv.DictReader(open('data.csv', encoding='utf-8')))</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>csv.DictReader</code> produit un<br/>
itérateur de dictionnaires (un par ligne, avec<br/>
pour clés les noms de l'en-tête) ; <code>list()</code> le<br/>
matérialise en table prête à l'emploi.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>list(csv.reader(open('data.csv', encoding='utf-8')))</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>csv.reader</code> produit des <strong>listes</strong>,<br/>
pas des dictionnaires, et la ligne d'en-tête<br/>
est lue comme les autres. Sur un fichier<br/>
<code>nom,age</code> on obtient<br/>
<code>[['nom', 'age'], ['Alice', '17'], ...]</code>, sans<br/>
accès par descripteur.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q09 : Nombre de lignes</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Comment obtenir le <strong>nombre d'enregistrements</strong><br/>
(lignes) d'une table représentée comme liste de<br/>
dictionnaires ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Pour le nombre de <strong>colonnes</strong>, on regarde les<br/>
clés du premier dictionnaire :<br/>
<code>len(table[0])</code> (en supposant la table non vide).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>size(table)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : pas de fonction <code>size</code> en Python<br/>
standard.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>len(table.keys())</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>.keys()</code> n'existe pas sur une<br/>
liste. Cela lève <code>AttributeError</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>len(table)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>len()</code> sur la liste donne le<br/>
nombre de dictionnaires, donc de lignes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>table.count</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>.count</code> est une <strong>méthode</strong> (qui<br/>
compte les occurrences d'un élément), il faut<br/>
l'appeler avec des parenthèses et un<br/>
argument.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q10 : Table vide</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Que vaut <code>len(table)</code> pour une table vide ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Toujours penser au cas de la table vide dans les<br/>
calculs : <code>moyenne = total / len(table)</code> lèverait<br/>
<code>ZeroDivisionError</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une exception est levée</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>len([])</code> renvoie <code>0</code> sans erreur.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>0</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>[]</code> (liste vide) contient<br/>
zéro élément.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>-1</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>len</code> n'est jamais négatif.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>None</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>len</code> renvoie toujours un entier.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q11 : Trier par descripteur</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>On dispose de la fonction clé<br/>
<pre><code>def age(ligne):
    return ligne["age"]</code></pre><br/>
Comment trier la table par âge <strong>croissant</strong> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Pour trier sans modifier la table d'origine :<br/>
<code>sorted(table, key=age)</code>. Pour un tri<br/>
<strong>décroissant</strong>, ajouter <code>reverse=True</code>. On passe<br/>
la fonction elle-même (<code>age</code>, sans parenthèses) :<br/>
c'est <code>sort</code> qui l'appelle sur chaque ligne.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>table.sort(key=age)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>key</code> indique la fonction qui<br/>
calcule, pour chaque ligne, la valeur sur<br/>
laquelle comparer. Ici <code>age</code> renvoie l'âge de<br/>
la ligne. Tri en place de la liste.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>table.sort(reverse=False)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>reverse=False</code> est déjà la valeur<br/>
par défaut, et il manque <code>key</code> : sans lui,<br/>
<code>sort</code> ne sait pas comparer deux<br/>
dictionnaires entre eux (<code>TypeError</code>).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>sorted(table, by=age)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>sorted</code> n'a pas d'argument <code>by</code><br/>
(<code>TypeError</code>). C'est <code>key=</code> qu'il faut.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>table.sort(age)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>sort</code> n'accepte aucun argument<br/>
positionnel (<code>TypeError</code>). La fonction de clé<br/>
doit être nommée : <code>key=age</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q12 : Sélectionner des colonnes</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Comment construire une nouvelle table <code>resultat</code> ne<br/>
contenant que les colonnes <code>nom</code> et <code>age</code> de <code>table</code><br/>
(sans les autres descripteurs) ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Cette opération consiste à <strong>extraire un<br/>
sous-ensemble de colonnes</strong> d'une table (on parle<br/>
aussi de projection). C'est l'une des manipulations<br/>
classiques de tables, au même titre que la<br/>
sélection de lignes, le tri ou la fusion. En<br/>
compréhension de liste :<br/>
<code>[{"nom": l["nom"], "age": l["age"]} for l in table]</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>resultat = []
for l in table:
    resultat.append(l[["nom", "age"]])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : syntaxe inspirée de <strong>pandas</strong>, pas de<br/>
Python standard. Un dictionnaire ne s'indexe pas<br/>
par une liste de clés (<code>TypeError</code>) : il faut<br/>
extraire chaque clé séparément.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>resultat = {}
for l in table:
    for k in ["nom", "age"]:
        resultat[k] = l[k]</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>resultat</code> est un <strong>dictionnaire</strong><br/>
unique dont on écrase les deux valeurs à chaque<br/>
ligne. On obtient le nom et l'âge de la dernière<br/>
ligne seulement, et non une table.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>resultat = []
for l in table:
    resultat.append({"nom": l["nom"], "age": l["age"]})</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : pour chaque ligne, on construit<br/>
un nouveau dictionnaire ne gardant que les deux<br/>
clés voulues, et on l'ajoute à la nouvelle<br/>
table.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>resultat = []
for l in table:
    for k in ["nom", "age"]:
        resultat.append({k: l[k]})</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : chaque tour ajoute un dictionnaire à<br/>
<strong>une seule</strong> clé. La table obtenue compte deux<br/>
fois plus de lignes que l'originale, le nom et<br/>
l'âge d'un même élève étant séparés sur deux<br/>
lignes.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q13 : Fusion de tables</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Soient deux tables <code>t1</code> et <code>t2</code> ayant les <strong>mêmes descripteurs</strong>. Comment obtenir une nouvelle table<br/>
contenant toutes les lignes de <code>t1</code> puis celles de<br/>
<code>t2</code> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Pour modifier <code>t1</code> <strong>en place</strong> au lieu de créer<br/>
une nouvelle table : <code>t1 += t2</code>, ou une boucle<br/>
qui ajoute chaque ligne de <code>t2</code> avec <code>append</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>t1.append(t2)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Attention : <code>append(t2)</code> ajouterait <code>t2</code><br/>
comme <strong>un seul élément</strong> (une liste de<br/>
listes), pas en fusionnant. Pour ajouter<br/>
les lignes une à une, il faudrait une<br/>
boucle : <code>for ligne in t2: t1.append(ligne)</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>fusion(t1, t2)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : pas de fonction <code>fusion</code> en Python<br/>
standard.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>t1.merge(t2)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : pas de méthode <code>.merge</code> sur les<br/>
listes (cela ressemble à du pandas).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>t1 + t2</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la concaténation de listes<br/>
(<code>+</code>) crée une nouvelle liste contenant tous<br/>
les éléments. Idiome Python standard.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q14 : Calculer une moyenne</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Comment calculer la <strong>moyenne</strong> des âges d'une<br/>
table avec un descripteur <code>age</code> (entier) ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Penser à gérer le cas de la table <strong>vide</strong><br/>
(division par zéro) : tester <code>if table:</code> avant<br/>
le calcul, ou utiliser<br/>
<code>sum(...) / len(table) if table else 0</code>.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>sum(ligne.age for ligne in table) / len(table)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un dictionnaire n'a pas d'attribut<br/>
<code>.age</code> (<code>AttributeError</code>). La valeur d'un<br/>
descripteur s'obtient par <code>ligne['age']</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>sum(ligne['age'] for ligne in table) / len(table[0])</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>len(table[0])</code> compte les<br/>
<strong>descripteurs</strong> de la première ligne (le<br/>
nombre de colonnes), pas le nombre de lignes.<br/>
Il faut diviser par <code>len(table)</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>sum(table['age']) / len(table)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>table</code> est une <strong>liste</strong>, on ne<br/>
peut pas l'indexer par chaîne. Lève<br/>
<code>TypeError</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>sum(ligne['age'] for ligne in table) / len(table)</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : on extrait la valeur <code>age</code><br/>
pour chaque ligne via une expression<br/>
génératrice, puis on divise par le nombre de<br/>
lignes.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q15 : Jointure simple</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Soient<br/>
<pre><code>eleves = [
    {"id": 1, "nom": "Alice"},
    {"id": 2, "nom": "Bob"}
]
notes = [
    {"id_eleve": 1, "matiere": "Maths", "note": 15},
    {"id_eleve": 2, "matiere": "NSI", "note": 18}
]</code></pre><br/>
Pour associer chaque note au nom de l'élève, on<br/>
effectue une <strong>jointure</strong>. Quel code l'implémente<br/>
correctement ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>C'est l'opération de <strong>fusion</strong> de deux tables sur<br/>
une clé commune. Pour gagner en performance, on<br/>
peut indexer <code>eleves</code> par <code>id</code> dans un dictionnaire<br/>
au préalable.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>for n in notes:
    for e in eleves:
        print(e["nom"], n["matiere"], n["note"])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : sans la condition d'égalité<br/>
<code>n["id_eleve"] == e["id"]</code>, on produit le<br/>
<strong>produit cartésien</strong> : chaque note est<br/>
associée à <strong>tous</strong> les élèves, pas au sien<br/>
(quatre lignes affichées au lieu de deux).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>for n in notes:
    for e in eleves:
        if n["id_eleve"] == e["id_eleve"]:
            print(e["nom"], n["matiere"], n["note"])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la clé commune ne porte pas le même<br/>
nom dans les deux tables : <code>"id"</code> dans<br/>
<code>eleves</code>, <code>"id_eleve"</code> dans <code>notes</code>.<br/>
<code>e["id_eleve"]</code> lève donc <code>KeyError</code> dès la<br/>
première comparaison.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>for n in notes:
    for e in eleves:
        if n["id_eleve"] == e["id"]:
            print(e["nom"], n["matiere"], n["note"])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : on parcourt les notes et,<br/>
pour chacune, on cherche l'élève<br/>
correspondant. On affiche <code>Alice Maths 15</code><br/>
puis <code>Bob NSI 18</code>. Complexité O(n × m).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>for n in notes:
    print(eleves[n["id_eleve"]]["nom"], n["matiere"], n["note"])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>eleves[1]</code> accède à l'<strong>indice 1</strong><br/>
de la liste, pas à l'élève d'<code>id</code> 1. Ici la<br/>
note de Maths est attribuée à Bob, puis<br/>
<code>eleves[2]</code> lève <code>IndexError</code>. Un identifiant<br/>
n'est pas un indice.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q16 : Pièges de conversion</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Après lecture d'un CSV avec <code>csv.DictReader</code>, on<br/>
veut calculer la moyenne des âges. Quel piège<br/>
faut-il éviter ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Piège classique chez les débutants : oublier la<br/>
conversion. Symptôme : addition qui concatène<br/>
des chaînes ou comparaison qui plante.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Le module <code>csv</code> ne gère pas les fichiers de plus de 100 lignes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : il gère sans problème des fichiers de<br/>
plusieurs millions de lignes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Toujours initialiser une variable globale</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Pas un piège spécifique au CSV.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Il faut payer une licence pour utiliser <code>csv.DictReader</code></p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : le module <code>csv</code> est gratuit et inclus<br/>
dans Python standard.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Oublier de convertir les valeurs en <code>int</code> (les valeurs lues sont des chaînes)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>csv.DictReader</code> ne fait<br/>
aucune conversion de type. <code>"17" + "16"</code><br/>
donne <code>"1716"</code>, pas <code>33</code>. Toujours convertir<br/>
avant de calculer.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q17 : Compter par catégorie</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Soit<br/>
<pre><code>table = [
    {"nom": "Alice", "ville": "Lyon"},
    {"nom": "Bob", "ville": "Paris"},
    {"nom": "Chloé", "ville": "Lyon"}
]</code></pre><br/>
Quel code construit le dictionnaire <code>c</code> donnant le<br/>
nombre d'élèves dans chaque ville, ici<br/>
<code>{"Lyon": 2, "Paris": 1}</code> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Schéma général du comptage par catégorie : un<br/>
dictionnaire dont les clés sont les catégories et<br/>
les valeurs les effectifs. Le test <code>if v in c</code><br/>
distingue la première rencontre d'une catégorie<br/>
(création de la clé) des suivantes (incrément).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>c = {}
for ligne in table:
    v = ligne["ville"]
    if v in c:
        c[v] = 1
    else:
        c[v] = c[v] + 1</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : les deux branches sont inversées. À la<br/>
première rencontre d'une ville, la clé <code>v</code><br/>
n'existe pas encore dans <code>c</code>, et <code>c[v] + 1</code><br/>
lève <code>KeyError</code> (ici dès <code>"Lyon"</code>). C'est la<br/>
première rencontre qui doit créer la clé à <code>1</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>c = {}
for ligne in table:
    v = ligne["ville"]
    if v in c:
        c[v] = c[v] + 1
    else:
        c[v] = 1</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : on construit progressivement<br/>
un dictionnaire <code>ville → effectif</code>. À la<br/>
première rencontre d'une ville, on crée la clé<br/>
avec la valeur <code>1</code> ; ensuite, on incrémente.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>c = {}
for ligne in table:
    v = ligne["ville"]
    if v in table:
        c[v] = c[v] + 1
    else:
        c[v] = 1</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : le test d'appartenance porte sur<br/>
<code>table</code>, qui ne contient que des dictionnaires,<br/>
jamais une chaîne : il est toujours faux et<br/>
chaque ville est remise à <code>1</code>. On obtient<br/>
<code>{"Lyon": 1, "Paris": 1}</code> : une présence, pas<br/>
un comptage.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>c = {}
for ligne in table:
    v = ligne["ville"]
    c[v] = table.count(v)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>count</code> cherche l'élément exact <code>v</code><br/>
(une chaîne) dans <code>table</code>, qui ne contient que<br/>
des dictionnaires : il renvoie toujours <code>0</code>.<br/>
On obtient <code>{"Lyon": 0, "Paris": 0}</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q18 : Tri sur deux critères</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Soit<br/>
<pre><code>table = [
    {"nom": "Lou", "age": 17},
    {"nom": "Bob", "age": 16},
    {"nom": "Ana", "age": 17}
]</code></pre><br/>
Quel code trie la table par <strong>âge croissant</strong>, puis<br/>
par <strong>nom alphabétique</strong> en cas d'égalité ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Astuce : la comparaison des tuples en Python est<br/>
lexicographique (premier élément, puis deuxième en<br/>
cas d'égalité), ce qui simplifie beaucoup les tris<br/>
sur plusieurs critères. La fonction clé renvoie le<br/>
tuple des critères dans l'ordre de priorité.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>def cle(l):
    return (l["age"], l["nom"])
table.sort(key=cle)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : la clé est un <strong>tuple</strong>.<br/>
Python compare les tuples élément par<br/>
élément : d'abord l'âge, puis le nom en cas<br/>
d'égalité. On obtient Bob (16), Ana (17),<br/>
Lou (17).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>def cle(l):
    return l["age"] + l["nom"]
table.sort(key=cle)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : on ne peut pas additionner un entier<br/>
et une chaîne (<code>TypeError</code>). Et même entre<br/>
chaînes, une concaténation ne définirait pas<br/>
un ordre sur deux critères.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>def cle(l):
    return (l["nom"], l["age"])
table.sort(key=cle)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : l'ordre des critères est inversé. Le<br/>
premier élément du tuple est le critère<br/>
principal, ici le nom. On obtient Ana, Bob,<br/>
Lou, sans tenir compte de l'âge.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>def cle(l):
    return l["age"]
table.sort(key=cle)</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : le tri ne porte que sur l'âge. En cas<br/>
d'égalité, <code>sort</code> conserve l'ordre initial des<br/>
lignes : on obtient Bob, Lou, Ana, et non Bob,<br/>
Ana, Lou.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q19 : Exemple concret</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Lequel des fichiers Open Data suivants se prête<br/>
naturellement à une représentation en table ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Open Data : data.gouv.fr, opendata.paris.fr,<br/>
INSEE... regorgent de jeux de données en CSV<br/>
directement utilisables.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>La liste des stations Vélib' au format CSV</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : un cas typique. Chaque ligne<br/>
= une station, descripteurs = nom,<br/>
longitude, latitude, capacité, etc. Idéal<br/>
pour traitement en table.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une carte des arrondissements de Paris au format SVG</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : SVG est un format vectoriel, pas<br/>
tabulaire.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un PDF illustré</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un PDF est un format de<br/>
présentation, mal adapté à la manipulation<br/>
tabulaire (sauf après extraction).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une vidéo de présentation des différents transports urbains</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : un fichier multimédia ne se<br/>
structure pas en table.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q20 : Limite des tables</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour quel type de données les tables sont-elles<br/>
<strong>mal adaptées</strong> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Règle générale : pour des données <strong>plates</strong>, la<br/>
table est adaptée ; pour des données <strong>hiérarchiques</strong><br/>
(comme un arbre généalogique), un format imbriqué<br/>
(JSON par exemple) est plus naturel.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une liste de produits avec prix</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Données plates : table parfaitement adaptée.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Un classement sportif officiel regroupant plusieurs équipes</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Données plates : table adaptée.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Un arbre généalogique avec des relations multiples</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : les relations<br/>
parent/enfant/conjoint sont <strong>hiérarchiques</strong>.<br/>
Les tables peuvent les stocker, mais ce n'est<br/>
pas la représentation la plus naturelle pour<br/>
ce type de données.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une liste d'élèves avec nom, âge, ville</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Données plates : parfaitement adaptées à<br/>
une table.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q21 : Trace d'accès</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Soit<br/>
<pre><code>t = [
    {"a": 1, "b": 2},
    {"a": 3, "b": 4},
    {"a": 5, "b": 6}
]</code></pre><br/>
Que vaut <code>sum(l["a"] for l in t if l["b"] &gt;= 4)</code> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Méthode : (1) appliquer le filtre <code>l["b"] &gt;= 4</code><br/>
à chaque ligne ; (2) extraire <code>l["a"]</code> pour les<br/>
lignes restantes ; (3) sommer.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>12</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : tu as additionné les <code>a</code> de toutes<br/>
les lignes (1 + 3 + 5) sans filtrer.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>8</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : les lignes filtrées sont<br/>
<code>{"a": 3, "b": 4}</code> (b=4 ≥ 4) et<br/>
<code>{"a": 5, "b": 6}</code> (b=6 ≥ 4). Somme des <code>a</code> :<br/>
3 + 5 = 8.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>0</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : il y a bien des lignes qui<br/>
satisfont <code>l["b"] &gt;= 4</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>9</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : tu as inclus la première ligne<br/>
(a=1) à tort. Or <code>b=2</code>, donc le filtre rejette.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q22 : Transformer la structure</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>On veut convertir la <strong>liste de dictionnaires</strong><br/>
<pre><code>table = [
    {"x": 1, "y": 2},
    {"x": 3, "y": 4}
]</code></pre><br/>
en <strong>dictionnaire de listes</strong> <code>{"x": [1, 3], "y": [2, 4]}</code><br/>
(représentation « colonne par colonne »), rangé<br/>
dans <code>colonnes</code>. Quel code est correct ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>La représentation colonne par colonne facilite les<br/>
calculs sur une colonne entière (somme, moyenne,<br/>
maximum de <code>colonnes["x"]</code>) sans reparcourir les<br/>
lignes. La transformation inverse (dictionnaire de<br/>
listes vers liste de dictionnaires) se fait de<br/>
façon symétrique.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<pre><code>colonnes = {}
for k in table[0]:
    colonnes[k] = [l[k] for l in table]</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : pour chaque clé du premier<br/>
dictionnaire (les descripteurs), on construit<br/>
la liste des valeurs de cette clé sur toutes<br/>
les lignes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>colonnes = {}
for k in table:
    colonnes[k] = [l[k] for l in table]</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>for k in table</code> parcourt les<br/>
<strong>lignes</strong> (des dictionnaires), pas les clés.<br/>
<code>l[k]</code> avec <code>k</code> dictionnaire lève <code>TypeError</code><br/>
(un dictionnaire ne peut pas servir de clé).<br/>
Il faut prendre les clés d'une ligne, par<br/>
exemple <code>table[0]</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>colonnes = {}
for l in table:
    for k in l:
        colonnes[k] = l[k]</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : on range une <strong>valeur</strong> et non une<br/>
liste, écrasée à chaque ligne. On obtient<br/>
<code>{"x": 3, "y": 4}</code> : seule la dernière ligne<br/>
subsiste.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<pre><code>colonnes = []
for k in table[0]:
    for l in table:
        colonnes.append(l[k])</code></pre>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>colonnes</code> est une simple liste plate,<br/>
<code>[1, 3, 2, 4]</code> : les noms de colonnes sont<br/>
perdus. Il faut un dictionnaire dont chaque<br/>
valeur est la liste d'une colonne.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q23 : Performance d'une jointure</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Pour une jointure entre deux tables de tailles<br/>
<code>n</code> et <code>m</code>, la version naïve à deux boucles<br/>
imbriquées a une complexité de O(n × m). Comment<br/>
l'améliorer ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>C'est exactement ce que font les SGBD avec leurs<br/>
<strong>index</strong> : transformer une recherche linéaire<br/>
en accès direct quasi instantané (table de<br/>
hachage ou arbre B).</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>En ne conservant que les colonnes utiles dans chacune des deux tables</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : la complexité dépend du <strong>nombre de<br/>
lignes</strong> parcourues, pas du nombre de colonnes.<br/>
Chaque ligne est plus légère, mais les deux<br/>
boucles imbriquées font toujours n × m<br/>
comparaisons.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>En triant d'abord les deux tables, tout en gardant les deux boucles imbriquées</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : trier ne sert à rien si l'on garde<br/>
ensuite les deux boucles imbriquées, qui font<br/>
toujours n × m comparaisons. Un tri n'accélère<br/>
une jointure que si l'algorithme en tire parti<br/>
(parcours simultané des deux tables triées), et<br/>
il coûte lui-même O(n log n).</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>En indexant l'une des deux tables par sa clé dans un dictionnaire</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : l'accès à un dictionnaire par<br/>
sa clé est en O(1). On construit l'index en un<br/>
seul parcours, avec <code>idx[e["id"]] = e</code> pour<br/>
chaque élève <code>e</code>, puis chaque note <code>n</code> ne<br/>
coûte qu'un accès : <code>e = idx[n["id_eleve"]]</code>.<br/>
La jointure passe de O(n × m) à O(n + m),<br/>
beaucoup plus rapide pour de gros volumes.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>En représentant chaque ligne par un tuple plutôt que par un dictionnaire</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : changer la représentation d'une ligne<br/>
ne change pas le nombre de comparaisons, les<br/>
deux boucles imbriquées font toujours n × m<br/>
tours. Ce n'est pas une optimisation<br/>
algorithmique.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q24 : Bug subtil</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Un élève construit une table à partir d'une liste<br/>
de noms :<br/>
<pre><code>noms = ["Alice", "Bob", "Chloé"]
ligne = {"nom": "", "age": 16}
table = []
for nom in noms:
    ligne["nom"] = nom
    table.append(ligne)
print(table[0]["nom"])</code></pre><br/>
Qu'affiche ce programme, et pourquoi ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Piège classique de construction d'une table : un<br/>
dictionnaire est un objet modifiable, et une liste<br/>
ne stocke que des références. Réutiliser le même<br/>
dictionnaire pour toutes les lignes produit une<br/>
table de lignes identiques. Il faut créer un<br/>
dictionnaire neuf pour chaque enregistrement.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="100" format="html">
    <text><![CDATA[<p><code>Chloé</code>, car les trois lignes sont le même dictionnaire, modifié à chaque tour</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Bonne réponse : <code>append</code> range dans la table<br/>
une référence vers <code>ligne</code>, jamais une copie.<br/>
Les trois éléments de <code>table</code> désignent le<br/>
même dictionnaire, dont la clé <code>"nom"</code> vaut<br/>
<code>"Chloé"</code> après le dernier tour. Correction :<br/>
créer un dictionnaire neuf à chaque tour, en<br/>
plaçant <code>ligne = {"nom": nom, "age": 16}</code> dans<br/>
la boucle.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>Alice</code>, car <code>append</code> range dans la table une copie de <code>ligne</code> à chaque tour</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>append</code> ne copie rien, il ajoute une<br/>
référence vers l'objet. Les trois lignes sont<br/>
le même dictionnaire, et <code>table[0]["nom"]</code><br/>
vaut <code>"Chloé"</code>.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p><code>Chloé</code>, car <code>append</code> insère chaque nouvelle ligne en tête de la table</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : <code>append</code> ajoute toujours en <strong>fin</strong><br/>
de liste. La valeur affichée est bien <code>Chloé</code>,<br/>
mais pour une autre raison : les trois lignes<br/>
sont le même dictionnaire.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Rien, car ajouter plusieurs fois le même dictionnaire à une liste lève une erreur</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Erreur : une liste peut contenir plusieurs fois<br/>
le même objet sans aucune erreur. Le programme<br/>
s'exécute et affiche <code>Chloé</code>.</p>]]></text>
    </feedback>
  </answer>
</question>

<question type="multichoice">
  <name>
    <text>Tables de données — Q25 : Synthèse</text>
  </name>
  <questiontext format="html">
    <text><![CDATA[<p>Parmi les affirmations suivantes sur les tables de<br/>
données, laquelle est <strong>fausse</strong> ?</p>]]></text>
  </questiontext>
  <generalfeedback format="html">
    <text><![CDATA[<p>Les tables de données et leurs opérations<br/>
associées (recherche, tri, fusion) sont au cœur<br/>
du traitement de données. Les maîtriser en<br/>
Python est un atout majeur pour<br/>
manipuler de gros volumes.</p>]]></text>
  </generalfeedback>
  <defaultgrade>1.0</defaultgrade>
  <penalty>0.0</penalty>
  <hidden>0</hidden>
  <single>true</single>
  <shuffleanswers>true</shuffleanswers>
  <answernumbering>abc</answernumbering>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Les opérations classiques sont la recherche, le tri, la sélection de lignes (filtrage), la sélection de colonnes et la fusion</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Vrai : ce sont les opérations canoniques sur<br/>
les tables, prévues par le programme.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>Une fusion permet de combiner deux tables sur la base d'un descripteur commun</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Vrai : c'est exactement le rôle de la fusion,<br/>
qui rapproche les lignes de deux tables<br/>
partageant une clé.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="0" format="html">
    <text><![CDATA[<p>En Python, on représente couramment une table par une liste de dictionnaires</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Vrai : c'est la représentation la plus<br/>
fréquente en NSI Première.</p>]]></text>
    </feedback>
  </answer>
  <answer fraction="100" format="html">
    <text><![CDATA[<p>Le module <code>csv</code> produit toujours des données typées (entiers, flottants, dates)</p>]]></text>
    <feedback format="html">
      <text><![CDATA[<p>Faux (donc bonne réponse) : <code>csv</code> produit<br/>
uniquement des <strong>chaînes</strong>. C'est au<br/>
programme de convertir les types.</p>]]></text>
    </feedback>
  </answer>
</question>

</quiz>
