É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?


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.


20

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

(setq a  (prog1 b (setq b  a)))

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))

:)


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.