Aller au contenu

Organisation d'une liste (déplacement d'un élément)


DenisHen

Messages recommandés

Bonjour à la communauté.
J'ai cherché dans mes tutos et mes Lisp téléchargés, mais je n'ai rien trouvé. Sauf si je n'ai pas lu avec attention 😢.
J'ai vu (vl-remove, je pense que c'est une idée à creuser, ou (permute (dans "Introduction à AutoLisp"), qui serait je pense le plus approprié.
J'aimerais faire une petite fonction qui déplacerait un élément d'une liste à l'intérieur de cette liste, exemple : 

(setq MaListe (list "Lundi" "Mercredi" "Mardi" "Jeudi" "Vendredi" "Samedi" "Dimanche"))

Et la fonction ressemblerait à ça :

(defun DeplElemList (List Old New /)
  ;; Liste = liste contenant les éléments
  ;; Old   = ancien emplacement de l'élément à déplacer
  ;; New   = nouvel emplacement de l'élément
;; C'est là que je ne sais pas comment faire pour être efficace   <--
)

Et on appellera la fonction

(setq NouvList (DeplElemList 2 1))

Mon problème principal est si j'ai ça (déplacer l'élément de plusieurs positions) 

(setq NouvList (DeplElemList 4 2))

Je n'arrive pas à écrire la fonction...
Quelqu'un aurait une idée ?
Denis...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Je suis sûr que l'on peut faire mieux, mais en version la plus simple (et intuitive peut-être) pour une permutation :

Tu crées une boucle pour parcourir ta liste avec un indice courant qui s'incrémente de 0 à n-1

Et 3 conditions :

 - si l'indice courant est égal à l'indice OLD tu ajoutes à la nouvelle liste, l'élément d'indice NEW

 - si l'indice courant est égal à l'indice NEW tu ajoutes à la nouvelle liste, l'élément d'indice OLD

 - sinon tu ajoutes l'élément d'indice courant

 

Olivier

Lien vers le commentaire
Partager sur d’autres sites

Salut Olivier et un grand merci pour ton aide.
J'y vais, mais c'est pô gagné...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Oui, je l'ai écris à la mano sur mon joli petit calepin.
Je suis passé au code...
Je cherche comment remplacé un élément dans une liste selon sa position (et non sa valeur) dans l'aide en ligne.
Car je ne veux pas utiliser (subst au cas ou il y ai plusieurs élément de même valeur.
Merci.

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Coucou, j'ai écris un code interminable qui, bien sur, ne fonctionne pas encore.😪
Certain sourirons à la vu de ce code, car ils savent déjà le faire en trois ou quatre lignes à coup de (mapcar et de (lambda...

(defun c:TestList (/ MaListe)
  (setq MaListe (list "Lundi" "Mardi" "Jeudi" "Mercredi" "Vendredi" "Samedi" "Dimanche"))
  (princ (DeplElemList MaListe 3 2))
  (princ)
) ;_ _defun
(defun DeplElemList (Liste Old New / ElemOld ElemNew NewList Pos)
  (princ "\nTest de déplacement d'un élément dans une liste.")
  (if (or (<= (length Liste) Old) (<= (length Liste) New))
    (progn (princ "\nUne des deux position est fausse") (exit))
  ) ;_ _if
  (setq ElemOld (nth Old Liste))
  (setq ElemNew (nth New Liste))
  (setq NewList (list))
  (setq Pos 0)
  (while (<= Pos (length Liste))
    (cond ((= Pos New) (setq NewList (append NewListe (list ElemNew))) (setq Pos 1+))
	  ((= Pos Old) (setq Liste (cdr Liste)))
	  (T (setq NewListe (append NewListe (list (car Liste)))) (setq Liste (cdr Liste)) (setq Pos 1+))
    ) ;_ _cond
  ) ;_ _foreach
) ;_ _defun

Le code est tellement "simple" aux yeux de certains qu'il sauront tout de suite me donner les bons conseils, seule raison de cette publication.😉
Je "dubite" beaucoup sur le choix du (while
J'ai la curieuse sensation de me noyer dans un verre d'eau, à moitié vide...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Au vu des innombrables essais sans résultat, j'ai changé mon fusil d'épaule et me suis dis :
Mais, pourquoi ne pas utiliser les super fonctions de Maître (gile), hein ?
Alors j'ai tenté des trucs, mais je me bute à mon ignorance en liste.
J'ai donc une petite question sur les Lisp de (gile).
Je reviendrais poster mes résultats, s'il sont bons, évidement 😉.

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Je le prends comme un challenge.

Une version avec un fonction auxiliaire récursive.

(defun deplace (lst old new / foo)
  (defun foo (x l o n)
    (cond
      ((and (null l) (< o 0) (< n 0)) nil)
      ((= o 0)
       (if (< n 0)
	 (cdr l)
	 (foo x (cdr l) (1- o) n)
       )
      )
      ((= n 0)
	(if (< o 0)
	  (cons x l)
	  (cons x (foo x l o (1- n)))
	)
      )
      (T (cons (car l) (foo x (cdr l) (1- o) (1- n))))
    )
  )
  (foo (nth old lst) lst old new)
)

La même dans un style impératif (avec while) :

(defun deplace (lst old new / item newList)
  (setq item (nth old lst))
  (while (or lst (<= 0 old) (<= 0 new))
    (cond
      ((= old 0)
       (setq old (1- old))
       (if (< new 0)
	 (setq newList (append (reverse (cdr lst)) newList)
	       lst     nil
	 )
	 (setq lst (cdr lst))
       )
      )
      ((= new 0)
       (setq new     (1- new))
       (if (< old 0)
	 (setq newList (append (reverse lst) (cons item newList))
	       lst     nil
	 )
	 (setq newList (cons item newList))
       )
      )
      (T
       (setq newList (cons (car lst) newList)
	     lst     (cdr lst)
	     old     (1- old)
	     new     (1- new)
       )
      )
    )
  )
  (reverse newList)
)

 

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

Lien vers le commentaire
Partager sur d’autres sites

Merci pour ton aide (gile).
Je le prend aussi comme un challenge.
Et je le ferais ! ! ! Non de non ! ! !
Avec un peu d'aide, mais pas avec un copier/coller.
Encore merci, je regarde dubitatif tes codes...
J'avoue ne pas bien comprendre ce que sont les variables x, l, o, n...
Je comprend mieux le mode impératif.

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

En fait, je suis maintenant sur ce type de code, que j'ai tout écris avec mes petits doigts...

(defun DeplElemList (Liste Old New / LstNew)
;;; Test en colsole :
;;; (setq Liste (list "Lundi" "Mardi" "Jeudi" "Mercredi" "Vendredi" "Samedi" "Dimanche"))
;;; (DeplElemList MaListe 4 3)
  (princ "\nTest de déplacement d'un élément dans une liste.")
  (if (or (<= (length Liste) Old) (<= (length Liste) New))
    (progn (princ "\nValeur(s) (Old ou New) fausse(s)") (exit))
  ) ;_if
  (setq LstNew (list))
  (if (< Old new)
    (progn (setq LstNew (gc:breakAt New Liste))
	   (setq LstNew (append (car LstNew) (list (nth New Liste)) (cdr LstNew)))
	   (setq LstNew (gc:breakAt (+ New 1) LstNew))
	   (setq LstNew (append (car LstNew) (cadr LstNew)))
    ) ;_ _progn
    (progn (setq LstNew (gc:breakAt New Liste))
	   (setq LstNew (append (gc:butLast (car LstNew)) (list (nth New Liste)) (cdr LstNew)))
	   (setq LstNew (gc:breakAt (- New 1) LstNew))
	   (setq LstNew (append (car LstNew) (cdr LstNew)))
    ) ;_ _progn
  ) ;_ _if
  (princ)
) ;_ _defun

Mais je maitrise encore très mal les listes, et ce n'est pas le manque de volonté ! ! ! 
J'y arriverais, j'y suis presque, et je ne vais pas craquer à trois mètres du bol de sangria tout de même...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Si tu veux utiliser des fonctions déjà écrites regarde du côté de gc:take et gc:skip issues de la librairie List en bas de cette page. Je te laisse chercher avant de donner une solution avec ces fonctions.

;; gc:take
;; Retourne les n premiers éléments de la liste
;;
;; Arguments
;; n : le nombre d'éléments
;; l : une liste
(defun gc:take (n l)
  (if (and l (< 0 n))
    (cons (car l) (gc:take (1- n) (cdr l)))
  )
)

;; gc:skip
;; Retourne la liste moins les n premiers éléments
;;
;; Arguments
;; n : le nombre d'éléments
;; l : une liste
(defun gc:skip (n l)
  (if (and l (< 0 n))
    (gc:skip (1- n) (cdr l))
    l
  )
)

 

il y a 18 minutes, DenisHen a dit :

J'avoue ne pas bien comprendre ce que sont les variables x, l, o, n...

Ce ne sont pas des variables, ce sont les arguments de la fonction foo.

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

Lien vers le commentaire
Partager sur d’autres sites

il y a 2 minutes, (gile) a dit :

Ce ne sont pas des variables, ce sont les arguments de la fonction foo.

Oops, "Erreur profonde de mes sens abusés" (de M. Pierre Dac il me semble).
J'avais choisi breakAt, mais je vais faire comme tu me dis, en plus, j'ai tes fonctions sous le nez....
Encre merci à toi...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Bonsoir,

 

Si je reprends : écrire la fonction en "français" c'est à dire comme un algorithme ça pourrait donner ça

; définit comme variable d'entrée : la liste MaListe , la variable Old : 1er indice à permuter, la variable New : 2nd indice à permuter
; les indices dans une liste commence à 0, mais tu souhaites compter à partir de 1 donc on enlève 1 pour convertir ton indice en indice base 0

; stocke le nombre d'élémentde MaListe dans la variable NbElt

; stocke/initialise la valeur 0 dans un compteur/indice nommé I 

; stocke/initialise une liste vide dans la variable NewList

; boucle sur les nombre d'élément de la liste

  ; SI le compteur (indice) est égal à Old-1 ALORS

    ; Ajoute l'élément d'indice New-1 à la nouvelle liste

    ; SINON, SI le compteur (indice) est égal à New-1 ALORS

      ; Ajoute l'élément d'indice Old-1 à la nouvelle liste

      ; SINON Ajoute l'élément d'indice courant à la nouvelle liste

  ; passe à l'élément suivant

; renvoie la nouvelle liste

 

Ensuite sous chaque ligne de commentaire tu écris la fonction lisp correspondante

; définit comme variable d'entrée : la liste MaListe , la variable Old : 1er indice à permuter, la variable New : 2nd indice à permuter
; les indices dans une liste commence à 0, mais tu souhaites compter à partir de 1 donc on enlève 1 pour convertir ton indice en indice base 0
(defun DeplElemList (MaListe Old New / i NewList)
  
  ; stocke le nombre d'élémentde MaListe dans la variable NbElt
  (setq NbElt (length MaListe))
  
  ; stocke/initialise la valeur 0 dans un compteur/indice nommé I 
  (setq I 0)
  
  ; stocke/initialise une liste vide dans la variable NewList
  (setq NewList nil)
  
  ; boucle sur les nombre d'élément de la liste
  (repeat NbElt
    
    ; SI le compteur (indice) est égal à Old-1 ALORS
    (if (= I (1- Old))
     
      ; Ajoute l'élément d'indice New-1 à la nouvelle liste
      (setq NewList (append NewList (list (nth (1- New) MaListe))))
      
      ; SINON, SI le compteur (indice) est égal à New-1 ALORS
      (if (= I (1- New))
       
        ; Ajoute l'élément d'indice Old-1 à la nouvelle liste
      	(setq NewList (append NewList (list (nth (1- Old) MaListe))))
        
        ; SINON Ajoute l'élément courant à la nouvelle liste
      	(setq NewList (append NewList (list (nth   I MaListe))))
      )
    )
     
    ; passe à l'élément suivant
    (setq I (1+ I))
  )
  
  ; renvoie la nouvelle liste
  NewList
)

 

Et voilà ...

Ce beaucoup moins fun à écrire que la fonction récursive de @(gile), mais comme dirait @didier autant commencer à apprendre à marcher avant de courir 🙂 

Il n'y a que 11 lignes que l'on peut encore raccourcir sans problème (remplacer les if par un cond par ex), mais comme chaque étape est décortiquée à son maximum, peu de risque de s'embrouiller les pinceaux.

 

Olivier

Lien vers le commentaire
Partager sur d’autres sites

Il semble que je n'ai pas compris tout à fait la même chose que @Olivier Eckmann. J'utilise un indice de base 0 parce que c'est "la norme" et que ce n'est pas la peine d'ajouter de la complexité. Et la fonction d'Oliver renvoie la même chose si on fait (DeplElemList lst 2 5) ou (DeplElemList lst 5 2).

Le plus simple, et ça t'aiderait aussi à y voir plus clair, serait de donner quelques exemples de résultats renvoyés sur une liste simple du style '(0 1 2 3 4 5 6).

_$ (deplace '(0 1 2 3 4 5 6) 0 6)
(1 2 3 4 5 6 0)
_$ (deplace '(0 1 2 3 4 5 6) 6 0)
(6 0 1 2 3 4 5)
_$ (deplace '(0 1 2 3 4 5 6) 2 4)
(0 1 3 4 2 5 6)
_$ (deplace '(0 1 2 3 4 5 6) 4 2)
(0 1 4 2 3 5 6)

 

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

Lien vers le commentaire
Partager sur d’autres sites

Bonjour à toutes et à tous, et mille mercis pour votre aide !
@Olivier Eckmann : un grand merci pour ce "pré-code", je n'avais pas fait pareil.
@(gile): c'est exactement ce que je cherche à faire.
Encore merci à vous tous, je m'y colle ce matin.
Denis...

Modifié par DenisHen
Correction pour Olivier Eckmann

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Il y a 3 heures, DenisHen a dit :

@Luna: un grand merci pour ce "pré-code", je n'avais pas fait pareil.

Luna ??!! Je pense qu'il faut que tu prennes un plus le temps de lire attentivement les messages...

La méthode proposée par  @Olivier Eckmann de commencer par écrire l'algorithme et de le transformer en commentaires dans le code est excellente.

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

Lien vers le commentaire
Partager sur d’autres sites

Oops, désolé @Olivier Eckmann, c'est que je lisais un autre poste de Luna justement...
Oui, j'ai adopté cette méthode pour ce code, mais n'étant pas habitué, c'était un peu "brouillon"...
Je fais toujours mes fenêtres à la main avant de les faire sur VBA ou DCL, maintenant, ce sera aussi les codes.
Encore merci à vous deux.

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

Une proposition tiré de cette discussion sans utiliser nth, (traité comme un chalenge perso pour l'approfondissement de ma compréhension du lisp).

(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
  )
)
_$ (moveFromTo 2 1 '("Lundi" "Mercredi" "Mardi" "Jeudi" "Vendredi" "Samedi" "Dimanche"))
("Lundi" "Mardi" "Mercredi" "Jeudi" "Vendredi" "Samedi" "Dimanche")

 

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Effectivement, j'avais mal lu le but du déplacement et j'étais parti sur une permutation au lieu d'un déplacement.

Dans ce cas l'algo est un peu différent

; définit comme variable d'entrée : la liste MaListe , la variable Old : ancienne position dans la liste, la variable New : nouvel position
; Je pars sur les indices en base 0 pour simplifier
(defun DeplElemList (MaListe Old New / i NewList)
  
  ; stocke le nombre d'élémentde MaListe dans la variable NbElt
  (setq NbElt (length MaListe))
  
  ; stocke/initialise la valeur 0 dans un compteur/indice nommé I 
  (setq I 0)
  
  ; stocke/initialise une liste vide dans la variable NewList 
  ; (inutile dans ce cas car définie comme variable locale donc initialiser à nil, 
  ; mais avant de construire une nouvelle liste par append bien penser à l'initialiser à nil)
  (setq NewList nil)
  
  ; boucle sur les nombre d'élément de la liste
  (repeat NbElt
    
    ; teste la valeur de I
          ; SI le compteur (indice) est égal à New ALORS
    (cond ((= I New)
     
           ; Ajoute l'élément d'indice Old à la nouvelle liste
           (setq NewList (append NewList (list (nth Old MaListe))))
      
           ; Ajoute l'élément d'indice courant à la nouvelle liste
           (setq NewList (append NewList (list (nth I MaListe))))
          )
      
          ; SI le compteur est égal à Old ALORS ne fait rien
	      ; SINON ajoute l'élément courant 
          ; Ces 2 dernières conditions peuvent être remplacées par celle ci
          ; SI le compteur (indice) est différent de Old ALORS
          ((/= I Old)
       
           ; Ajoute l'élément d'indice courantà la nouvelle liste
      	   (setq NewList (append NewList (list (nth I MaListe))))
          )
    )
     
    ; passe à l'élément suivant
    (setq I (1+ I))
  )
  
  ; renvoie la nouvelle liste
  NewList
)

 

Ca pourrait être ma version "piou piou qui apprend le chasse neige" 🙂 

 

Olivier

Lien vers le commentaire
Partager sur d’autres sites

On m'a appelé ? ^^'

J'arrive un peu après la guerre donc je ne pourrais proposer plus que ce qui a déjà été fait. En revanche en LISP, la maîtrise des listes est primordial et apprendre à faire mumuse avec ainsi est très certainement le meilleur moyen d'apprendre :3

Le principal n'est pas d'arriver à une solution parfaite, mais plutôt de trouver la solution qui te correspond au mieux et cela tu l'as très bien compris ! Donc bon courage pour le reste et à force de pratiquer tu finiras par apprivoiser les fonctions (mapcar) et (lambda), et même si tu n'y parviens pas tu trouveras un chemin alternatif : le tiens 😉

PS: désolée si je ne suis plus aussi active qu'à mon habitude depuis quelques temps..cela devrait s'arranger d'ici peu 🙂

Bisous, Luna

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é