Échangez deux variables dans Elisp

20

Supposons que j'ai

(setq a 1 b 2)

Comment permuter élégamment les valeurs de aet bsans utiliser de variable temporaire?

PythonNut
la source
Bien que je me souvienne de l'opération de swap d'exemples de programmation il y a de nombreuses années, je ne pense pas avoir jamais eu besoin d'une telle opération de "swap". Alors, où trouvez-vous que vous avez besoin d'une telle chose?
Stefan
@Stefan cette fois, j'écris une fonction qui prend deux arguments, et je voudrais m'assurer que le premier argument est le plus petit des deux.
PythonNut
1
@PythonNut, vous pouvez bien lier le premier argument à (min a b)et le second à (max a b). Ceci est une solution. Certains diront que cela nécessite deux comparaisons lorsque l'une suffit, c'est vrai. Vous pouvez le gérer avec une seule comparaison de manière plus fonctionnelle, par exemple en utilisant la liaison de déstructuration (cl-destructuring-bind (a . b) (if (< a b) (cons a b) (cons b a)) ...). C’est une autre façon.
Mark Karpov
1
@Mark true, mais, au moins pour moi, cela ressemble à tapoter des mouches avec des grenades à main. cl-destructuring-bindest un outil ridiculement puissant pour ce travail.
PythonNut

Réponses:

18

Si la mémoire me sert bien et que vous êtes prêt à l'utiliser, cl-libalors:

(cl-rotatef a b)

Notez que c'est une façon Common Lisp de résoudre le problème.

Mark Karpov
la source
20

C'est l'idiome élégant que j'utilise ;-).

(setq a  (prog1 b (setq b  a)))
A dessiné
la source
1
Hé, c'est bien. Je garderai cela à l'esprit si la performance est un problème.
PythonNut
1
Ingénieux et simple.
Nom du
1
Oh, ce n'est pas original avec moi, en aucune façon. Mais c'est probablement la principale utilisation que j'en fais prog1.
Drew
1
C'est à peu près ce à quoi la cl-rotatefmacro se développe.
abo-abo
6

S'il s'agit d'entiers:

(setq a (logxor a b))
(setq b (logxor a b))
(setq a (logxor a b))

:)

jtgd
la source
2
Pour être complet, vous devez également inclure le classique suivant: a = a + b, b = a - b, a = a - b. Traduit à Emacs Lisp, bien sûr :-D
Mark Karpov
1
Certes, et pour être complet, je ferai remarquer qu'en asm ou en C, The XOR Trick fonctionne pour tout; registres, mémoire, ints, flottants, structs, chaînes (longueur égale) ... En Lisp je pense que les ints. Pour les gros blocs de mémoire, il est agréable de ne pas avoir besoin du tampon temporaire.
jtgd
@jtgd: Pour les gros blocs de mémoire, vous pouvez effectuer le swap segment par segment, avec un petit tampon.
Clément