Troque duas variáveis ​​no Elisp


20

Suponha que eu tenha

(setq a 1 b 2)

Como posso trocar elegantemente os valores de ae bsem usar uma variável temporária?


Embora eu me lembre da operação de troca de exemplos de programação muitos anos atrás, acho que nunca precisei de uma operação de "troca". Então, onde você acha que precisa disso?
Stefan

@ Stefan neste momento, estou escrevendo uma função que recebe dois argumentos, e gostaria de garantir que o primeiro argumento seja o menor dos dois.
precisa saber é o seguinte

1
@ PythonNut, bem, você pode vincular o primeiro argumento (min a b)e o segundo (max a b). Esta é uma solução. Alguns argumentam que isso requer duas comparações quando uma basta, isso mesmo. Você pode lidar com isso com uma comparação ainda mais funcional, por exemplo, usando a ligação de desestruturação (cl-destructuring-bind (a . b) (if (< a b) (cons a b) (cons b a)) ...). Esta é outra maneira.
Mark Karpov

1
@ Mark verdade, mas, pelo menos para mim, parece que voa golpeando com granadas de mão. cl-destructuring-bindé uma ferramenta ridiculamente poderosa para este trabalho.
precisa saber é o seguinte

Respostas:


18

Se a memória me servir bem e você estiver disposto a usar, cl-libentão:

(cl-rotatef a b)

Observe que essa é a maneira Common Lisp de resolver o problema.


20

Este é o idioma elegante que eu uso ;-).

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

1
Ei, isso é legal. Vou me lembrar disso se o desempenho for uma preocupação.
precisa saber é o seguinte

1
Engenhoso e simples.
Nome

1
Oh, não é original para mim, por qualquer meio. Mas é provavelmente o principal uso que faço prog1.
21415 Drew

1
Isso é basicamente o que a cl-rotatefmacro expande.
abo-abo

6

Se for números inteiros:

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

:)


2
Para completar, você também deve incluir o seguinte clássico: a = a + b, b = a - b, a = a - b. Traduzido para Emacs Lisp, é claro :-D
Mark Karpov

1
É verdade, e para ser completo, vou apontar que, em asm ou C, o The XOR Trick funciona para qualquer coisa; registros, memória, ints, floats, structs, strings (comprimento igual) ... No Lisp, acho que apenas ints. Para grandes blocos de memória, é bom não precisar do buffer temporário.
Jtgd

@ jtgd: Para grandes blocos de memória, você pode fazer a troca segmento por segmento, com um pequeno buffer.
Clément
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.