Aller au contenu

Déplacer un élement d'une liste


Clément.a

Messages recommandés

Salut,

 

Si tu connais l'élément dans la liste tu peux utiliser la fonction gc:insertAt qui insère l'élément à l'index spécifié dans la liste

 

;; gc:insertAt
;; Insère l'élément dans la liste à l'index
;;
;; Arguments
;; ele : l'élément à insérer
;; ind : l'index auquel insérer l'élément
;; lst : la liste dans laquelle insérer l'élément
(defun gc:insertAt (ele ind lst)
 (cond
   ((null lst) nil)
   ((zerop ind) (cons ele lst))
   ((cons (car lst) (gc:insertAt ele (1- ind) (cdr lst))))
 )
)

 

Pour déplacer l'élément spécifié à l'index :

(if (vl-position ele lst)
 (gc:insertAt ele ind (vl-remove ele lst))
)

 

Pour déplacer un élément d'un index à un autre, le plus simple est d'utiliser une autre routine qui supprime l'élément à l'index spécifié.

 

Première solution en utilisant gc:insertAt et une autre routine : gc:removeAt

;; gc:removeAt
;; Retourne la liste privée de l'élément à l'index spécifié
;;
;; Arguments
;; ind : l'index auquel supprimer l'élément
;; lst : la liste dans laquelle isupprimer l'élément
(defun gc:removeAt (ind lst)
 (if (or (zerop ind) (null lst))
   (cdr lst)
   (cons (car lst) (gc:removeAt (1- ind) (cdr lst)))
 )
)

 

Utilisation :

(if (setq ele (nth fromIndex lst))
 (gc:insertAt ele toIndex (gc:removeAt fromIndex lst))
)

 

 

Ceci peut être optimisé en ne parcourant qu'une fois la liste jusqu'au plus grand des deux index.

C'est un peu moins simple, il faut envisager les cas où l'index de départ est inférieur ou supérieur à celui d'arrivée.

;; gc:moveFromTo
;; Déplace l'élément dans la liste d'un index à un autre
;;
;; Argument
;; from : index de départ
;; to   : index de destination
;; lst  : liste
(defun gc:moveFromTo (from to lst / loop ele)
 
 (defun loop (from to lst)
   (cond
     ((null lst) (list ele))
     ((zerop from)
      (if (< 0 to)
 (loop (1- from) to (cdr lst))
 (cdr lst)
      )
     )
     ((zerop to)
      (if (< 0 from)
 (cons ele (loop from (1- to) lst))
 (cons ele lst)
      )
     )
     (T (cons (car lst) (loop (1- from) (1- to) (cdr lst))))
   )
 )
 
 (if (and (setq ele (nth from lst)) (/= from to))
   (loop from to lst)
   lst
 )
)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

OK merci,

 

En revanche avec

;; gc:insertAt
;; Insère l'élément dans la liste à l'index
;;
;; Arguments
;; ele : l'élément à insérer
;; ind : l'index auquel insérer l'élément
;; lst : la liste dans laquelle insérer l'élément
(defun gc:insertAt (ele ind lst)
 (cond
   ((null lst) nil)
   ((zerop ind) (cons ele lst))
   ((cons (car lst) (gc:insertAt ele (1- ind) (cdr lst))))
 )
)

pas moyen de metre l'élément à la fin de la liste c'est normale ou je fait une mauvaise manip ?

Lien vers le commentaire
Partager sur d’autres sites

Bon j'avai besoin de cette fonction pour modifier un xrecord et comme avec cons ça place l'élément au début le entmakex ne marchais pas (enfin je pense que c'est pour ça) du coup j'ai utiliser insertAt or quand j'ai une liste de paire pointé comme un xrecord il ne veut pas applique le (cons ele lst)(sa ne modifie pas la liste dans le condition ( zerop ind)

du coup je sais pas si c'est moi qui fait pas bien ou si il y a un problème ?

 

Merci

 

Réponse :

 

Erreur de ma part il manquait un petit "setq" devant le (insertAt ele ind lst)

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

pas moyen de metre l'élément à la fin de la liste c'est normale ou je fait une mauvaise manip ?

 

Une petite coquille dans le code remplace l’expression ((null lst) nil) par ((null lst) (list ele))

 

Le code

(defun insertAt (ele ind lst)
 (cond
   ((null lst) (list ele))
   ((zerop ind) (cons ele lst))
   ((cons (car lst) (insertAt ele (1- ind) (cdr lst)))))  
)

 

Pour tester

_$ (setq lst '(A B C D E))
(A B C D E)
_$ (insertAt 'F 5 lst)
(A B C D E F)
_$

 

 

Sinon pour faire echo à la proposition précédente de (gile) et pour le jeu une variante plus compacte, sans recourir à la fonction nth pour lire la valeur en from et ne parcourir qu’une seul fois la liste.

(defun moveFromTo (from to lst / loop ele)
 (defun loop (from to lst)
   (cond ((minusp (max from to)) lst)
         ((zerop from) (setq ele (car lst)) (loop (1- from)  to (cdr lst)))
         ((zerop to) ((lambda (l) (cons ele l)) (loop from (1- to) lst)))
         (T (cons (car lst) (loop (1- from) (1- to) (cdr lst))))
   )
 )
 (if (/= from to)
   (loop from to lst)
   lst
 )
)

 

A+

 

 

(Nb: Les amateurs apprécirons l’astuce avec l’usage de lambda pour différer l’évaluation de ele jusqu’à la descente complète des appels pour être certain de son affectation lors de la remonté des appels enveloppants, quelques soit le plus grand des 2 index.)

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Re,

 

Bon j'avai besoin de cette fonction pour modifier un xrecord et comme avec cons ça place l'élément au début le entmakex ne marchais pas (enfin je pense que c'est pour ça) du coup j'ai utiliser insertAt or quand j'ai une liste de paire pointé comme un xrecord il ne veut pas applique le (cons ele lst)(sa ne modifie pas la liste dans le condition ( zerop ind)

du coup je sais pas si c'est moi qui fait pas bien ou si il y a un problème ?

 

As te lire, je suis persuadé que si tu avais posté des exemples codés, de ce que tu n’arrivais pas à faire, nous aurions certainement pu te montrer comment le faire au moyen des fonctions assoc, member, subst et append..

 

Car si tu travailles avec des listes de définition organisées sous forme de listes associatives (clef valeur) accessible avec la fonction assoc, tu t’apercevras que "bien souvent" la position des listes n’a que peu d’importance. C’est là la force des listes associatives dans la gestion des données.

 

Exemple :

(entmake (cons '(0 . "CIRCLE") (list '(8 . "CalqueCercle") '(10 0.0 0.0 0.0) '(40 . 100.0))))

Est pour AutoCAD aussi recevable que :

(entmake (cons '(0 . "CIRCLE") (reverse (list '(8 . "CalqueCercle") '(10 0.0 0.0 0.0) '(40 . 100.0)))))

 

 

pas moyen de metre l'élément à la fin de la liste c'est normale ou je fait une mauvaise manip ?

Au cas ou si tu ne veux que positionner un élément en fin de liste, les classiques du lisp :

$ (append '(A B C D) (list 'E))
(A B C D E)

Ou

_$ (reverse (cons 'E (reverse '(A B C D))))
(A B C D E)

 

A+

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Parfait Merci VDH-Bruno en tout cas je trouve très astucieux comment fonctionne la fonction insertAt!

Merci à tous

 

 

C’est de mon point de vue la façon la plus naturel de parcourir une liste, une liste étant une structure définie de façon récursive, je trouve plus agréable de la parcourir de la même manière..

 

Si tu n’es pas trop à l’aise avec la notion de récursivité, quelques liens à consulter…

http://cadxp.com/index.php?/topic/29314-ces-listes-qui-nen-sont-pas/

http://cadxp.com/index.php?/topic/10999-recursivite/

http://cadxp.com/index.php?/topic/29587-mecanique-de-la-recursion/

http://cadxp.com/index.php?/topic/5381-alternatives-a-vlisp-recursivite/

 

A+

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Salut

 

Pour le plaisir

Une sans boucle, juste de la manipulation de liste (par contre, pas de doublon dans la liste)

(defun insertAt (ele ind lst)
 (if (member (nth ind lst) lst)
   (append (reverse (cdr (member (nth ind lst) (reverse lst))))
    (cons ele (member (nth ind lst) lst))
   )
   (append lst (list ele))
 )
)

 

Et une autre en itérative, juste histoire de ne pas faire que du récursif

(defun insertAt (ele ind lst / n l)
 (setq n 0)
 (while (< n ind)
   (setq l (cons (car lst) l)
  lst (cdr lst)
  n (1+ n)
   )
 )
 (append (reverse (cons ele l)) lst)
)

 

@+

Les Lisps de Patrick

Le but n'est pas toujours placé pour être atteint, mais pour servir de point de mire.

Joseph Joubert, 1754-1824

Lien vers le commentaire
Partager sur d’autres sites

Et une autre en itérative, juste histoire de ne pas faire que du récursif

 

Dans ce cas ;)

(defun insertAt (ele ind lst / x)
 (if (> ind (length lst))
   (setq ind (length lst))
 )
 (mapcar '(lambda (a)
            (cond (x (setq ele x x a) ele)
                  ((zerop ind) (setq x a) ele)
                  (T (setq ind (1- ind)) a)
            )
          )
         (append lst (list T))
 )
)

 

A+

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Toujours pour le jeu, la variante avec foreach, comme cela il n’y aura pas eu que du récursif.. :)

 

(defun insertAt (ele ind lst / val)
 (if (> ind (length lst))
   (append lst (list ele))
   (reverse (foreach x lst
              (if (zerop ind) (setq val (cons ele val)))
              (setq ind (1- ind) val (cons x val))
            )
   )
 )
)

 

Amicalement Bruno

 

 

Nb : Les versions mapcar et foreach étant évidemment moins bonne, car elles s’appliquent sur toutes les cellules cons de la liste, même si l’indice spécifié ne concerne que la tête de liste..

Modifié par VDH-Bruno

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Sinon pour faire echo à la proposition précédente de (gile) et pour le jeu une variante plus compacte, sans recourir à la fonction nth pour lire la valeur en from et ne parcourir qu’une seul fois la liste.

(defun moveFromTo (from to lst / loop ele)
 (defun loop (from to lst)
   (cond ((minusp (max from to)) lst)
         ((zerop from) (setq ele (car lst)) (loop (1- from)  to (cdr lst)))
         ((zerop to) ((lambda (l) (cons ele l)) (loop from (1- to) lst)))
         (T (cons (car lst) (loop (1- from) (1- to) (cdr lst))))
   )
 )
 (if (/= from to)
   (loop from to lst)
   lst
 )
)

 

A+

 

 

(Nb: Les amateurs apprécirons l’astuce avec l’usage de lambda pour différer l’évaluation de ele jusqu’à la descente complète des appels pour être certain de son affectation lors de la remonté des appels enveloppants, quelques soit le plus grand des 2 index.)

 

Force m'est de constater qu'on touche là à l'excellence.

Bravo !

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Merci a vous deux !

 

Force m'est de constater qu'on touche là à l'excellence.

Bravo !

 

C'est toujours plus facile de jouer en deuxième, et si tel était vraiment le cas, j’aurais dû écrire ;) :

(defun bv:moveFromTo (from to lst / loop ele)
 (defun loop (from to lst)
   (cond ((minusp (max from to)) lst)
         ((zerop from) (setq ele (car lst)) (loop (1- from) to (cdr lst)))
         ((zerop to) ((lambda (l) (cons ele l)) (loop from (1- to) lst)))
         (T (cons (car lst) (loop (1- from) (1- to) (cdr lst))))
   )
 )
 (loop from to lst)
)

 

La condition (/= from to) n’est pas indispensable, la fonction loop est suffisamment généraliste…

 

A+

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Je viens de tomber sur ce poste et il y a une remarque que je n'ai pas très bien compris sur l'usage du lambda :

(Nb: Les amateurs apprécirons l’astuce avec l’usage de lambda pour différer l’évaluation de ele jusqu’à la descente complète des appels pour être certain de son affectation lors de la remonté des appels enveloppants, quelques soit le plus grand des 2 index.)

 

Cela veut dire que lors de l'utilisation d'un lambda dans une boucle récursive celui ci est évalué qu'au retour ?

www.le-metal.net, sur la métallerie
Lien vers le commentaire
Partager sur d’autres sites

Bonjour Titifonky,

 

Je viens de tomber sur ce poste et il y a une remarque que je n'ai pas très bien compris sur l'usage du lambda :

 

 

Cela veut dire que lors de l'utilisation d'un lambda dans une boucle récursive celui ci est évalué qu'au retour ?

 

En quelque sorte, l’explication en est très simple pour cela il suffit de se rappeler qu’un programme Lisp (list processing), s’interprète comme une liste de la gauche vers la droite.

 

 

 

Dans la fonction récursive loop, si nous avions définit la ligne du cond de la façon suivante :

      ((zerop to)  (cons ele  (loop from (1- to) lst)))

 

Lorsque l’indice de l’élément from est supérieur à l’indice de déplacement to, la ligne de code sera évaluée, en commençant par l’expression la plus à gauche c’est-à-dire la valeur de l’élément ele qui vaut nil (car a ce stade sa valeur ne lui a pas encore été affecté), cet état est empilé (mémorisé) puis la fonction loop est appelle..

 

Une fonction lisp retourne toujours son résultat là ou elle a été appellé donc au retour d’appel la valeur nil précédemment interprété sera "consé".

 

 

 

Pour pallier à cette difficulté, on a fait appel à une fonction auxiliaire, comme c’est pour un usage unique et localisé, j’ai utilisé une fonction anonyme lambda (elle aurait pu être nommé pour un usage moins localisé, et même récursive quand l’algorithme si prête => voir ICI pour un cas basique de récursion croisée)

 

Pour en revenir à notre fonction lambda, l’écriture suivante :

      ((zerop to) ((lambda (l) (cons ele l)) (loop from (1- to) lst)))

 

Fait que la fonction loop devient argument de la fonction lambda, en conséquence elle est d’abord interprété puis c’est sa valeur de retour qui est transmise à la fonction lambda pour que cette dernière puisse à son tour être interprété et que soit "conser" la valeur de ele sur la liste partiel retourné par la fonction loop.

 

A ce stade on est sûr que la valeur variable ele est affecté d’une valeur car son interprétation n’est plus effectué pendant la descente des appels récursif (avec une affectation ou absence d’affectation suivant l’ordre des indices from et to), mais la variable ele est interprété pendant la remonté (dépilement) des appels .

 

 

 

J’espère avoir été suffisamment explicite, l’idée général dans ce style d’exercice est de percevoir l’interprétation d’une fonction lisp sous forme de transmission d’expression, d’évaluation et de valeur en retour..

 

A+ Bruno

 

 

(Ps : Félicitation pour ton site Titifonky, je viens d’y jeter un œil, j’aime beaucoup, bravo !)

Modifié par VDH-Bruno

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Ok, je comprends, très jolie solution. Merci pour l'explication.

Pour résumer, l'élément ele qui était un des arguments de la fonction 'cons' est deplacé dans une fonction équivalente à 'cons' mais ayant comme seul argument le retour de la fonction loop, ce qui permet de différer sont évaluation à la remonté de la récursion.

www.le-metal.net, sur la métallerie
Lien vers le commentaire
Partager sur d’autres sites

Oui, tout à fait cela permet d’inverser l’ordre d’évaluation des termes de la fonction cons par l’interpréteur Lisp.

 

Un équivalent de cette ligne de code :

   ((zerop to) ((lambda (l) (cons ele l)) (loop from (1- to) lst)))

par composition de fonctions serait :

   ((zerop to) (apply 'cons (reverse (list (loop from (1- to) lst) ele))))

 

A+

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

(Ps : Félicitation pour ton site Titifonky, je viens d’y jeter un œil, j’aime beaucoup, bravo !)

 

Titifonky n'en est pas à son premier compliment, n'est-ce pas ? D'ailleurs il ne sait pas que j'ai bientôt un article pour lui ;)

 

PS : ce forum lisp est pas mal aussi, faudrait en parler :P

Bureau d'études dessin.

Spécialiste Escaliers

Développement - Formation

 

./__\.
(.°=°.)
Lien vers le commentaire
Partager sur d’autres sites

Titifonky n'en est pas à son premier compliment, n'est-ce pas ? D'ailleurs il ne sait pas que j'ai bientôt un article pour lui ;)

 

PS : ce forum lisp est pas mal aussi, faudrait en parler :P

 

C'est vrai que ça fait toujours plaisir ;)

 

Surtout que j'ai un peu abandonné AutoCad ces derniers temps au profit de Solidworks, a part pour le traitement de fichiers en "masse" avec le lisp bien sûr.

 

Tiens, j'ai completement oublié de mettre un lien vers ce forum, j'y vais de ce pas le crier haut et fort sur les toits, enfin sur la toile.

 

Un article pour moi, je suis impatient de le lire !!!!!

www.le-metal.net, sur la métallerie
Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité