9
votes

Comment puis-je réutiliser une recherche gethash en commun Lisp?

J'ai une table de hachage où les clés sont des listes assez complexes, avec des sublistes de symboles et d'entiers, et la valeur doit être modifiée en fonction de la valeur déjà existante. La table est créée avec : test # 'égale .

Je fais quelque chose de similaire à celui-ci: xxx

profilage indique que EQUAL Les tests prennent beaucoup de temps. J'ai une idée d'optimisation que la quantité de recherche gethash pourrait être réduite de deux à une. Cela peut être fait en C ++ en réutilisant l'itérateur, mais je ne sais pas comment cela serait fait dans Lisp. Des idées?


0 commentaires

6 Réponses :


0
votes

Certaines solutions de contournement peuvent être:

Si le modèle commun est RECHERCHE -> Recherche-it -> écrasé-it, vous pouvez remplacer le type de valeur à une liste contenant le type de valeur. Ensuite, après avoir trouvé l'objet de valeur pour la clé, remplacez simplement son premier élément, par exemple P>

* (defparameter *my-hash* (make-hash-table))
*MY-HASH*

* (setf (gethash :my-key *my-hash*) (list "old-value"))
("old-value")

* (gethash :my-key *my-hash*)
("old-value")
T

* (defparameter old-value-container (gethash :my-key *my-hash*))
OLD-VALUE-CONTAINER

* (setf (first old-value-container) "new value")
"new value"

* (gethash :my-key *my-hash*)
("new value")
T


4 commentaires

J'ai essayé quelque chose de similaire au code source que vous avez posté, mais lorsque vous faites la (Setf (première vieille liste) ...), il n'allume que l'ancienne liste et la modification ne se reflète pas dans la valeur de la table de hachage. Suis-je mal comprendre quelque chose de fondamental?


@ Kotlinski: Si vous avez fait que la valeur initiale de l'ancienne liste est nulle, alors oui, cela ne sera pas reflété dans la valeur de la table de hachage. Cependant, si vous avez déjà une liste, alors Gethash renvoie la liste et vous pouvez la muter de la manière dont vous pensez. Remarque, "Push" ne fonctionnera pas car cela affecte la variable que vous appuyez sur, en ajoutant une nouvelle tête et définissez la variable à pointer sur cette nouvelle valeur. Il partagera ensuite une partie de la liste avec la valeur Hashtable (en supposant que cela ne soit pas nul), mais pas la même chose.


"Les structures de données intégrées de LISP communes sont notoirement opaques." -- que veux-tu dire?


La discussion à reddit.com/r/programming/commentes/7sab5/... < / a> démontre certaines des critiques. Ce n'est pas une attaque de la langue, mais plutôt une observation sur la manière dont certaines de ses constructions intégrées sont architectes. Je supprime la note de notoriété cependant - cela n'ajoute pas de valeur à cette réponse.



0
votes

Une chose que vous pourriez faire est d'utiliser Devtructeur pour créer une valeur que chaque entrée de votre table de hachage pointe. Votre liste de valeurs (que vous appuyez sur dans votre exemple actuel) pourrait être stockée à l'intérieur. La création de struct pourrait être effectuée dans cet appel Gethash initial (en tant que valeur par défaut) ou pourraient être effectués manuellement si vous observez qu'il n'y a pas de valeur là-bas. Ensuite, l'objet peut être effectué de manière intérieure de la manière dont vous faites.

(Cela ignore la question de savoir si vous voulez vraiment utiliser des valeurs aussi complexes telles que vos touches de hashtable, ou s'il y a un moyen de contourner cela. Par exemple, vous pouvez utiliser des structures / des objets rapprochés au lieu de complexes. Liste comme vos clés, puis vous pouvez utiliser une haquetable EQ à la place. Mais cela dépend beaucoup de ce que vous faites.)


0 commentaires

0
votes

"Le profilage montre que des tests égaux prennent une longue durée."

Oui, mais avez-vous vérifié que # 'Equal Les recherches de table de hasch prennent aussi beaucoup de temps?

Avez-vous compilé ceci pour une vitesse sur un compilateur d'optimisation comme SBCL et regardé les notes du compilateur?

Après avoir résolu ces deux questions, vous pouvez également essayer une table de hachage imbriquée pour chaque niveau de vos clés de liste. Il ne devrait pas être difficile d'écrire une macro pour des tables de hachage imbriquées arbitrairement.


0 commentaires


0
votes

Peut-être que je manque quelque chose d'évident, mais: xxx

depuis:

  • nil est déjà la valeur par défaut pour gethash
  • Gethash tire l'objet entier afin que vous puissiez simplement le modifier en place plutôt que de dire à pousser comment le regarder à nouveau
  • (point de style: Utilisez quand au lieu de si il n'y a pas de clause d'autre)

    EDIT: Oups, j'étais: j'ai raté le cas où l'ancien-i est nul. Mais si ce n'est pas le cas commun, alors, cela pourrait toujours être une victoire, car vous n'avez besoin que de la recherche dans ce cas: xxx

    hmm, cela fonctionne-t-il? < / p>


1 commentaires

Non, ça ne le fait pas. Vous appuyez sur les articles sur le lieu Old-i Lieu qui n'a aucun effet sur ce qui est stocké dans le (gethash ...) place, puisque les listes LISP non vides sont des pointeurs à un nœud de tête et non de conteneurs.



1
votes

Vous pouvez accéder à la table de hachage trois fois. Pourquoi? Parce que la macro code> push code> peut développer le code qui fait un gethash code> pour obtenir la liste, puis certains System :: SemeHash CODE> Opération pour stocker la valeur .

Dans ce problème, vous inspectez la valeur d'un lieu, qui est une liste. Si cette liste satisfait un test de prédicat, vous appuyez sur quelque chose sur cet endroit. P>

Ce problème peut être attaqué en créant un opérateur spécial qui capture cette sémantique: P>

> (macroexpand '(push-if new test (gethash a b)))
(LET*
 ((#:VALUES-12736 (MULTIPLE-VALUE-LIST (VALUES A B)))
  (#:G12732 (POP #:VALUES-12736)) (#:G12733 (POP #:VALUES-12736)))
 (LET ((#:G12735 (GETHASH #:G12732 #:G12733)))
  (WHEN (FUNCALL TEST #:G12735) (SETF #:G12734 (CONS NEW #:G12735))
   (SYSTEM::PUTHASH #:G12732 #:G12733 #:G12734)))) ;


0 commentaires