Parcours
/
jq
jq
/
Exercices
/
Statistiques de notes
Statistiques de notes

Statistiques de notes

Exercice d'apprentissage

Introduction

Reduce

Supposons que l'on veuille additionner un tableau de nombres. Il existe de nombreuses façons d'atteindre ce but.

  • Dans de nombreux langages, ce problème s'exprime sous la forme d'une boucle avec une variable d'accumulation.

  • Ce problème peut s'écrire sous la forme d'une fonction récursive. En pseudo-code, on pourrait avoir ceci.

    function Add(X, Sum=0):
      if X is empty then
        return Sum
      else
        return Add(rest(X), Sum + first(X))
      end
    end
    

    Cette méthode, qui consiste à diviser le problème en plus petits morceaux, peut aussi se décrire comme le fait de « réduire vers le cas de base ».

Reduce est une façon de combiner tous les éléments d'une structure de données en une seule valeur. Le processus parcourt la structure de données en appliquant une fonction à chaque élément pour mettre à jour le résultat accumulé.

Dans jq, ce processus est implémenté par le filtre reduce. Dans d'autres langages, on l'appelle parfois « fold », « fold-left », « inject » ou « aggregate ».

L'expression reduce de jq ressemble à ceci.

reduce STREAM_EXPRESSION as $var (INITIAL_VALUE; UPDATE_EXPRESSION)
  • STREAM_EXPRESSION est un stream d'éléments, chacun stocké tour à tour dans la variable $var.
    • Pour rappel, pour créer un stream à partir d'un tableau, utilise le filtre itérateur .[] : $myArray | .[].
  • INITIAL_VALUE est la valeur de départ du résultat accumulé (appelé « accumulateur »).
  • L'UPDATE_EXPRESSION combine (« fold ») la valeur courante ($var) dans l'accumulateur.
    • Dans le contexte de cette expression, . est la valeur de l'accumulateur.
    • Le résultat de l'expression est stocké dans l'accumulateur pour être utilisé à l'itération suivante.
    • Après la dernière itération, le résultat accumulé est la sortie de reduce.

Prenons un exemple : additionner les nombres d'un tableau. Le filtre add fait exactement cela, mais on va voir comment l'implémenter.

Si on utilise [10, 20, 30, 40] comme entrée et zéro comme état initial, voici à quoi ressemble chaque étape.

# état élément réducteur résultat
1 0 10 0 + 10 10
2 10 20 10 + 20 30
3 30 30 30 + 30 60
4 60 40 60 + 40 100

En syntaxe jq, cela ressemble à ce code.

0 + 10 | . + 20 | . + 30 | . + 40

On peut exprimer cela avec le filtre reduce.

[10, 20, 30, 40] | reduce .[] as $n (0; . + $n)     # => 100
Note

La fonction native add est en réalité implémentée avec reduce, mais elle utilise « null » comme état initial (n'importe quel type de données peut être ajouté à null).

def add: reduce .[] as $x (null; . + $x);

Quelques points à garder en tête

  • Dans l'expression de réduction, . est l'accumulateur. Si l'entrée est un objet auquel tu dois faire référence à l'intérieur de la fonction de réduction, tu dois le stocker dans une variable.

    {"apple": 10, "banana": 16, "carrot": 4}
    | . as $obj
    | reduce (keys | .[]) as $key (0; . + $obj[$key])     # => 30
    
  • L'accumulateur peut être de n'importe quel type de données. Par exemple, tu peux vouloir inverser un tableau.

    ["A", "B", "C", "D"]
    | reduce .[] as $elem ([]; [$elem] + .)       # => ["D", "C", "B", "A"]
    

Instructions

Tu es professeur. À la fin de l'année, tu as attribué une note chiffrée à chacun de tes élèves. Tu dois maintenant la traduire en lettre et compter combien d'élèves ont obtenu chaque lettre

1. Traduis une note chiffrée en lettre

La fonction letter_grade prend une note chiffrée en entrée et renvoie la lettre correspondante. Utilise les intervalles suivants :

Lettre Note
A 90 % - 100 %
B 80 % - 89 %
C 70 % - 79 %
D 60 % - 69 %
F 0 % - 59 %

Exemple :

75 | letter_grade   # => "C"

2. Compte le nombre d'élèves pour chaque lettre

La fonction count_letter_grades prend un objet qui associe le nom des élèves à leurs notes. Le résultat est un objet qui associe chaque lettre au nombre d'élèves ayant obtenu cette note.

Exemple :

{"Joe": 78, "Jane": 93, "Richard": 72} | count_letter_grades
# => {"A": 1, "B": 0, "C": 2, "D": 0, "F": 0}

Il existe plusieurs façons de résoudre ce problème. Utilise le filtre reduce pour t'entraîner.

Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
jq Exercism

Prêt à commencer Statistiques de notes ?

Inscris-toi sur Exercism pour apprendre et maîtriser jq avec 12 concepts75 exercices, et un vrai mentorat humain, le tout gratuitement.