Scambia due variabili in Elisp


20

Supponiamo di averlo fatto

(setq a 1 b 2)

Come posso scambiare elegantemente i valori di ae bsenza usare una variabile temporanea?


Mentre ricordo l'operazione di scambio da esempi di programmazione molti anni fa, non credo di aver mai avuto bisogno di un'operazione di "scambio". Allora, dove trovi di aver bisogno di una cosa del genere?
Stefan,

@Stefan questa volta, sto scrivendo una funzione che accetta due argomenti e vorrei assicurarmi che il primo argomento sia il più piccolo dei due.
PythonNut,

1
@PythonNut, bene puoi associare il primo argomento al (min a b)secondo (max a b). Questa è una soluzione. Alcuni sosterranno che ciò richiede due confronti quando uno è sufficiente, giusto. Puoi gestirlo con un confronto in modo ancora più funzionale, ad esempio utilizzando il binding destrutturante (cl-destructuring-bind (a . b) (if (< a b) (cons a b) (cons b a)) ...). Questo è un altro modo.
Mark Karpov,

1
@Mark vero, ma, almeno per me, mi sembra di schiacciare le mosche con le bombe a mano. cl-destructuring-bindè uno strumento ridicolmente potente per questo lavoro.
PythonNut,

Risposte:


18

Se la memoria mi serve bene e sei disposto a usare cl-liballora:

(cl-rotatef a b)

Si noti che questo è il modo Common Lisp per risolvere il problema.


20

Questo è il linguaggio elegante che uso ;-).

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

1
Ehi, è pulito. Lo terrò a mente se le prestazioni sono sempre un problema.
PythonNut,

1
Geniale e semplice.
Nome

1
Oh, non è originale con me, in alcun modo. Ma è probabilmente l'uso principale che faccio prog1.
Drew

1
È praticamente ciò a cui si cl-rotatefespande la macro.
abo-ABO

6

Se sono numeri interi:

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

:)


2
Per completezza dovresti anche includere il seguente classico: a = a + b, b = a - b, a = a - b. Tradotto in Emacs Lisp, ovviamente :-D
Mark Karpov il

1
È vero, e per completezza sottolineo che in asm o C The XOR Trick funziona per qualsiasi cosa; registri, memoria, ints, float, struct, stringhe (uguale lunghezza) ... In Lisp penso solo ints. Per grandi blocchi di memoria è bello non aver bisogno del buffer temporaneo.
jtgd

@jtgd: per blocchi di memoria di grandi dimensioni, è possibile eseguire lo scambio segmento per segmento, con un piccolo buffer.
Clément,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.