Une tâche à base itération comme cela est le mieux adapté à son Common Lisp extrêmement puissant loop
macro. Vous pouvez lire tous les détails de cette macro dans the GigaMonkeys book, mais nous allons simplement passer en revue les parties dont vous avez besoin pour ce problème ici. Commençons par la définition de la fonction.
(defun lenguages (names)
...)
nous voulons Dans ce, à itérer sur la liste fournie. Nous voulons également collecter des clés, donc une table de hachage serait utile. Les tables de hachage (appelées cartes ou dicts dans de nombreuses autres langues) associent les clés aux valeurs de manière efficace.
(loop with hash = (make-hash-table)
for entry in names
for name = (car entry)
do ...
finally ...)
La macro loop
est très puissant et a un langage qui lui est propre. La clause with
déclare une variable locale, dans ce cas une table de hachage. Le premier for
définit une variable d'itération. La boucle fonctionnera avec entry
lié à chaque entrée de names
et s'arrêtera lorsqu'il n'y aura plus d'entrées. La troisième ligne est une autre variable locale, mais contrairement à with
, une variable for
est rebondie à chaque fois, donc à chaque itération name
sera le premier élément de entry
. Le bloc do
contient du code Lisp arbitraire qui sera exécuté à chaque itération et finally
contient un bloc de code Lisp à exécuter à la fin de la boucle.
À l'intérieur du bloc do
, nous souhaitons ajouter le nom de la personne à l'entrée de la table de hachage pour chaque langue connue. Nous avons donc besoin d'un autre loop
pour parcourir les langues connues.
(loop for lang in (cdr entry)
do (push name (gethash lang hash)))
Cette boucle va à l'intérieur du bloc do
de l'une extérieure. Pour chaque langue de la liste des langues connues de la personne, nous souhaitons ajouter le nom de cette personne à la valeur de hachage de cette langue. Normalement, nous devrions considérer le cas dans lequel la clé de hachage n'existe pas, mais heureusement pour nous Common Lisp par défaut à nil
si la clé de hachage n'existe pas, et en ajoutant un élément à nil
crée une liste d'un élément, ce qui est juste ce que nous voulons.
Maintenant, lorsque cette boucle est terminée, la table de hachage contiendra toutes les langues et clés et listes de personnes qui les connaissent comme valeurs. Ce sont les données que vous voulez, mais ce n'est pas dans le format que vous voulez.En fait, si nous mettons cela dans notre finally
bloc
(return hash)
Nous obtiendrions une sortie semi-utile * qui nous dit que nous sommes sur la bonne voie. Au lieu de cela, faisons une autre boucle pour convertir cette table de hachage à la liste que vous voulez qu'elle soit. Voici ce que nous voulons dans le bloc finally
maintenant.
(return (loop for key being the hash-keys of hash using (hash-value value)
collect (list key value)))
Il utilise la syntaxe being
relativement obscure pour la loop
macro, ce qui permet l'itération facile sur les tables de hachage. Vous devriez lire ceci: pour chaque paire clé-valeur, collecter une liste contenant la clé suivie de la valeur dans une liste, puis retourner la liste accumulée. C'est encore une des caractéristiques intéressantes des macros loop
: il essaie de fournir des primitives pour des cas d'utilisation courants tels que l'accumulation de valeurs dans une liste. Et il est utile dans les cas comme celui-ci.
Voici le bloc de code complet.
(defun lenguages (names)
(loop with hash = (make-hash-table)
for entry in names
for name = (car entry)
do (loop for lang in (cdr entry)
do (push name (gethash lang hash)))
finally (return (loop for key being the hash-keys of hash using (hash-value value)
collect (list key value)))))
Ce lien que je fourni plus tôt est le livre de GigaMonkeys sur Common Lisp, qui est available online for free. Je vous encourage fortement à le lire, car c'est une référence incroyable pour tout ce qui est commun. Surtout si vous débutez, ce livre peut vraiment vous mettre dans la bonne direction.
* Votre format de sortie peut varier. L'implémentation choisit comment générer les structures.
est un bonne réponse. Vous pourriez envisager d'utiliser push à la place de setf viz (push name (gethash lang hash '()) c'est un peu plus concis –
Gah tu as raison Ma tête pensait automatiquement "J'aimerais avoir' appendf 'ici" j'ai oublié que "pousser" était une chose. –
Merci pour la réponse, fonctionne parfaitement !. Mon dernier doute est s'il existe un moyen de montrer le résultat comme l'exemple que j'ai mis. J'ai essayé avec Format t mais ne fonctionne pas. –