-
Compteur de contenus
12 247 -
Inscription
-
Dernière visite
-
Jours gagnés
209
Type de contenu
Profils
Forums
Calendrier
Blogs
Tout ce qui a été posté par (gile)
-
@x_all, plutôt qu'utiliser une variable inutile, ce qui t'oblige à utiliser (progn ...) (progn (setq lstR (cdr lstR)) (doublon lstR) )tu peux écrire simplement : (doublon (cdr lstR)) @Fraid, celle là je l'adore (d'habitude c'est plutôt en VB qu'on voit ça), tant qu'à faire dans le verbeux, vas-y carrément : (if (/= (length lst) (length (remove-doubles lst))) T nil )qui est exactement équivalent à : (/= (length lst) (length (remove-doubles lst)))
-
Bravo à tous les deux, vous avez répondu à la demande, après, c'est juste une question d'élégance du code. @GEGEMATIC, on doit pouvoir supprimer certaines redondances @x_all, tu peux éviter tous les (setq ...), par exemple : (progn (setq lstR (cdr lstR)) (doublon lstR) )peut s'écrire beaucoup plus simplement.
-
Tu vois que c'est possible ;)
-
Et pourtant, une liste LISP est une liste chaînée, structure qui est une forme d'arbre binaire (voir ici).
-
Salut, Pour faire suite à ce sujet qui fait suite à celui-là, je propose un challenge (assez) facile pour aborder la récursivité dans un cadre où elle est incontournable. Il s'agit simplement de définir une fonction qui retourne la liste des chemins de tous les dossiers et sous dossiers contenus dans un dossier (voir la fonction vl-directory-files). Choisir un dossier avec des sous-dossiers à différents niveaux d'imbrication. Avec cette arborescence : http://gilecad.azurewebsites.net/Resources/arborescence.png La fonction doit retourner cette liste : ( "C:\\Temp\\dossier racine\\Dossier 1" "C:\\Temp\\dossier racine\\Dossier 1\\Sous dossier 1.1" "C:\\Temp\\dossier racine\\Dossier 1\\Sous dossier 1.1\\Bidule" "C:\\Temp\\dossier racine\\Dossier 1\\Sous dossier 1.1\\Truc" "C:\\Temp\\dossier racine\\Dossier 1\\Sous dossier 1.1\\Truc\\Machin" "C:\\Temp\\dossier racine\\Dossier 1\\Sous dossier 1.2" "C:\\Temp\\dossier racine\\Dossier 2" "C:\\Temp\\dossier racine\\Dossier 2\\Sous dossier 2.1" "C:\\Temp\\dossier racine\\Dossier 2\\Sous dossier 2.2" ) Merci à ceux qui l'ont déjà fait (ou qui savent le faire) de laisser chercher les autres.
-
Je pense que ce challenge est suffisamment facile pour que ceux-là se retiennent.
-
1+ avec Patrick_35 seul le traitement des structures de données récursives (typiquement les arborescences) nécessite un traitement récursif. Mais parfois la récursivité permet de résoudre simplement des problèmes complexes (fonction factorielle ou suite de Fibonacci pour les exemples les plus courant). Et il est des individus qui "pensent récursif" ou pour qui l'approche récursive récursive est plus immédiate que l'approche itérative. À ce propos, je pense que tu peux aussi mettre un handicap d'une journée à VDH-bruno. Pour plus coller au sujet qui a motivé ce challenge je vais en proposer un autre facile.
-
C'est exactement ce que fait la fonction récursive donnée en exemple ici. Si on fait un pas à pas : ;; empilement (sum '(5 (9 4) (6 (1 1)) 3)) (+ 5 (sum '((9 4) (6 (1 1)) 3))) (+ 5 (+ (sum '(9 4)) (sum '((6 (1 1)) 3)))) ; (sum '(9 4)) est le calcul d'une branche (+ 5 (+ (+ 9 (sum '(4))) (sum '((6 (1 1)) 3)))) (+ 5 (+ (+ 9 (+ 4 (sum ()))) (sum '((6 (1 1)) 3)))) (+ 5 (+ (+ 9 (+ 4 0)) (sum '((6 (1 1)) 3)))) (+ 5 (+ (+ 9 (+ 4 0)) (+ (sum '(6 (1 1))) (sum '(3))))) ; (sum '(6 (1 1))) calcul d'une branche (+ 5 (+ (+ 9 (+ 4 0)) (+ (+ 6 (sum '(1 1))) (sum '(3))))) ; (sum '(1 1)) calcul d'une branche (+ 5 (+ (+ 9 (+ 4 0)) (+ (+ 6 (+ 1 (sum '(1)))) (sum '(3))))) (+ 5 (+ (+ 9 (+ 4 0)) (+ (+ 6 (+ 1 (+ 1 (sum ())))) (sum '(3))))) (+ 5 (+ (+ 9 (+ 4 0)) (+ (+ 6 (+ 1 (+ 1 0))) (sum '(3))))) (+ 5 (+ (+ 9 (+ 4 0)) (+ (+ 6 (+ 1 (+ 1 0))) (+ 3 (sum ()))))) ;; dépilement (+ 5 (+ (+ 9 (+ 4 0)) (+ (+ 6 (+ 1 (+ 1 0))) (+ 3 0)))) (+ 5 (+ (+ 9 4) (+ (+ 6 (+ 1 (+ 1 0))) (+ 3 0)))) (+ 5 (+ 13 (+ (+ 6 (+ 1 (+ 1 0))) (+ 3 0)))) (+ 5 (+ 13 (+ (+ 6 (+ 1 1)) (+ 3 0)))) (+ 5 (+ 13 (+ (+ 6 2) (+ 3 0)))) (+ 5 (+ 13 (+ 8 (+ 3 0)))) (+ 5 (+ 13 (+ 8 3))) (+ 5 (+ 13 (+ 8 3))) ; résultats des feuilles et sommes par branche (+ 5 (+ 13 11)) (+ 5 24) 29 Mais cet algorithme un peu naïf qui traite chaque branche élément par élément n'est pas très efficient et servait surtout à illustrer mon propos. Les fonctions d'ordre supérieur permettent de traduire de façon déclarative (quasiment mot pour mot l'algorithme) : la somme des feuilles d'une branche, c'est la somme de ses feuilles et des sommes des feuilles de ses branches. (defun sum (l) (apply '+ (mapcar '(lambda (x) (if (listp x) (sum x) x ) ) l ) ) ) Le pas à pas est alors bien plus concis : (sum '(5 (9 4) (6 (1 1)) 3)) (apply '+ (list 5 (sum '(9 4)) (sum '(6 (1 1))) 3)) (apply '+ (list 5 (apply '+ (list 9 4)) (sum '(6 (1 1))) 3)) ; dépilement de (sum '(9 4)) (apply '+ (list 5 13 (sum '(6 (1 1))) 3)) (apply '+ (list 5 13 (apply '+ (list 6 (sum '(1 1)))) 3)) ; dépilement de (sum '(6 (1 1))) (apply '+ (list 5 13 (apply '+ (list 6 (apply + (list 1 1)))) 3)) ; dépilement de (sum '(1 1)) (apply '+ (list 5 13 (apply '+ (list 6 2)) 3)) (apply '+ (list 5 13 8 3)) (+ 5 13 8 3) 29
-
:blink: :blink: Là on atteint des sommets, même en corrigeant le fautes d'orthographes on est au delà de la poésie surréaliste... Je crois qu'il est grand temps que tu relèves la tête et que tu prennes un peu de recul (ou de repos). Tant que tu n'arriveras à énoncer clairement pour le commun des mortels ce que tu souhaites faire, tu ne pourras pas concevoir un programme pour un ordinateur qui ne fait qu’obéir à des instructions sans être capable de comprendre tes intentions.
-
Non, si tu ne regardes pas la chose d'un point de vue métier mais d'un point de vue structure de données, une "jonction" est une liste du même type qu'un "Debit". Toujours en essayant de rester générique, et comme déjà dit précédemment : (defun traiterbranche (branche) (foreach feuille branche (if (= (car feuille) "Debit") (traiterdebit feuille) (traiterjonction feuille) ) ) ) (defun traiterarbre (arbre) (foreach branche arbre (traiterbranche branche) ) )
-
Je n'ai pas compris parce que je ne fais aucun effort. C'est pour essayer de te pousser à t'expliquer de la manière la plus symbolique (mathématique) possible, avec recul, sans référence au métier. Quand tu codes, tu t'adresses à l'interpréteur LISP qui ne sais pas ce qu'est un Té, une Bouche, une Jonction... Si je parle de feuille et de branche, c'est parce que ce sont les termes symbolique couramment utilisés quand on parle de traitement de structures arborescentes. Que tu aies deux types de feuilles ne change rien à la structure générale de ton "arbre", tu peux dire qu'une "branche" peut potentiellement porter des "feuilles" et des "fruits". Ce qu'il faut que intègres, c'est que si une "branche" ne peut porter que des "feuilles" et des "fruits" mais aucune autre "branche", alors ta structure n'est pas une structure récursive. Structure non récursive : Un "arbre" est une liste de "branches". Une "branche" est une liste de "feuilles" et de "fruits". Structure récursive : Un "arbre" est une "branche". Une "branche" est une liste de "feuilles", de "fruits" et de "branches" (qui sont autant de listes de "feuilles", de "fruits" et de "branches"...) Comme dit plus haut, si tu n'as pas eu besoin d'utiliser la récursivité pour construire ton arbre (la liste) je vois mal comment ça pourrait être une structure récursive donc pourquoi tu aurais besoin d'utiliser la récursivité pour le parcourir (à part pour le fun).
-
Typiquement le genre phrase incompréhensible pour moi. D'où la difficulté à t'aider concrètement. Dans tous les cas pourquoi on "passe le 1er élément à la fin" si on est absolument sûr de ne pas y revenir ?
-
Ça sent fort le risque de boucle infinie...
-
(defun c:fredel (/ pline) (and (setq pline (car (entsel "\nSélectionnez une polyligne: "))) ; s'il n'y a pas de sélection, on sort (= (getpropertyvalue pline "LocalizedName") "Polyligne") ; si la propriété "LocalizedName" de pline n'est pas "Polyligne", on sort (command "_.text" pause "" "" (rtos (/ (getpropertyvalue pline "Length") 1000.))) ) (princ) ) La fonction 'and' utilise une ce qu'on appelle une évaluation short circuit, c'est à dire qu'à la première expression qui retourne nil, l'évaluation s'arrête et and renvoie nil. L'expression (setq ...) affecte à 'pline' la valeur retournée par (car (entsel ...)) et retourne cette valeur, Si aucun objet n'a été sélectionné cette valeur est nil, on sort. L'expression (= ...) évalue si 'pline' est bien une polyligne, si ce n'est pas le cas, on sort.
-
Toutes ces "branches" sont similaires (une liste de sous-listes de même format) et aucune ne contient de "sous-branche". C'est comme si tu avais un dossier qui contient n sous-dossiers chacun contenant un certains nombre de fichiers (mais pas de dossiers). Ce serait un arbre contenant uniquement des branches qui ne contiennent que des feuilles On ne peut pas vraiment parler d'arborescence, en tout cas pas de structure récursive dans la mesure où au deuxième niveau d'imbrication on tombe toujours sur une feuille du type (nom_du_bloc 1 position 1 handle1), jamais sur une autre branche. Si l'exemple que tu as donné est représentatif de ta structure, tu n'as pas besoin de récursivité, un foreach te permet de parcourir chaque "branche" et pour chacune, un autre foreach te permet de parcourir chaque feuille. Si tu n'as pas utilisé de fonction récursive pour générer cette liste, tu ne devrais pas avoir besoin de fonction récursive pour la parcourir. Si ta structure est vraiment de type récursif tu dois pouvoir la définir comme une branche contenant potentiellement des feuilles et des branches (cette définition est récursive). Dans ce cas : C'est précisément ça un traitement récursif, un arbre est une branche, donc tu traites l'arbre comme tu traites une branche. Si j'ai chois un exemple trivial pour illustrer mon propos, c'est pour faire ressortir le principe du fonctionnement des appels récursifs, mais en définissant des fonctions séparées pour le calcul de ces conditions (en général des prédicats qui retournent T ou nil) tu devrais pouvoir écrire une fonction 'explore' aussi claire et concise que 'sum'.
-
Je n'avais pas compris ça, dans ton exemple 'lsbrrecur' ne décrit pas une arborescence. Si tes données sont structurées en arbre (structure récursive), commence par poser le problème en décrivant la structure de façon récursive. Typequement, un arbre est une branche qui peut soit être vide, soit contenir des feuilles et / ou des branches. Quand tu as clairement décrit ce qu'est une feuille, tu parcours ton arbre de façon récursive en traitant chaque cas : - un arbre vide est une condition d'arrêt, - une feuille peut aussi être une condition d'arrêt ou avoir un traitement particulier dans un appel récursif, - une branche est traitée récursivement. Petit exemple simple avec un arbre dont les feuilles sont des nombres, les branches sont des listes contenant des nombres et/ou des branches. (setq arbre '( 5 (9 4) (6 (1 1)) 3 ) ) Si je veux faire la somme de tous les nombres (feuilles), j'utilise un algorithme récursif qui colle à la description récursive de la structure. La somme de toutes les feuilles d'une branche est égale à : - 0 si la branche est vide - si le premier élément de la branche est une feuille : la valeur d'une feuille plus la somme de toutes les feuilles du reste de la branche si le premier élément de la branche est une branche : la somme de toutes les feuilles de cette branche plus la somme de toutes les feuilles du reste de la branche. (defun sum (l) (cond ((null l) 0) ; la branche est vide (condition d'arrêt) ((numberp (car l)) ; le premier élément est une feuille (+ (car l) (sum (cdr l))) ; on l'ajoute à la somme du reste de la branche ) (T ; le premier élément est une branche (+ (sum (car l)) (sum (cdr l))) ; on ajoute la somme de cette branche à la somme du reste de la branche ) ) ) Si tu trace la fonction sum (trace sum) tu pourras voir dans la fenêtre de suivi comment les appels récursif traitent toutes les branches.
-
On progresse, si "branche" veut bien dire sous-liste (élément de la liste principale "arbre"), il n'y a rien de récursif dans cet énoncé, juste un traitement pour chaque élément d'une liste. (foreach branche arbre (traitement branche) ) (defun traitement (branche / ...) ...)
-
Commande interdites en éditeur de bloc
(gile) a répondu à un(e) sujet de Aleck_Ultimate dans AutoCAD 3D
Salut, L'éditeur de bloc est arrivé avec les blocs dynamiques spécifiquement pour paramétrer des actions dynamiques. Pour modifier une définition de bloc, tu peux toujours utiliser l'ancienne commande qui permet d'éditer le bloc dans le dessin REFEDIT (_EDITREF). -
Salut, Une fonction qui n'a pas d'effet de bord (on parle de "fonction pure"), c'est une fonction qui n'a aucun effet sur son environnement (la fonction parent qui l'appelle ou le programme), comme une fonction mathématique. Elle nécessite généralement des arguments et retourne une valeur, résultat du traitement des arguments. En général, une fonction LISP qui retourne toujours nil est une fonction a effet de bord : (command ...) retourne toujours nil et modifie l'environnement AutoCAD, c'est une fonction a effet de bord. Mais ce n'est si simple : (getvar ...) retourne la valeur de la variable système mais ne modifie rien (c'est une fonction pure) (setvar ...) retourne une valeur (l'argument valeur ou nil) mais modifie l'environnement). Pour les fonctions définies avec defun, si on ne veut pas d'effet de bord avec l'environnement LISP (modification de variables), il faut que toutes les valeurs en entrée (input) soient passées en argument, que toutes les variables définies dans la fonction soient déclarées et que la fonction ait une valeur de retour.
-
Tu décris l'algorithme (comment faire), mais personnellement je n'ai toujours pas compris l'énoncé du problème (quelles sont les données et à quoi aboutir). C'est à dire la première étape de l'élaboration d'une fonction (ou d'un programme). Si tu veux écrire une fonction récursive, il faut que tu commence par déterminer son (ou ses) argument(s) et sa valeur de retour (les données et l'objectif du problème). Il faut ensuite que tu détermines la condition d'arrêt, c'est à dire la valeur de l'argument pour laquelle la fonction s'arrête et retourne une valeur. Il faut aussi que la fonction modifie l'argument avant de le passer à l'appel récursif de façon à tendre vers la condition d'arrêt. fonction récursive : si l'argument rempli la condition d'arrêt alors on retourne la valeur sinon on appelle récursivement la fonction en lui passant l'argument modifié
-
J'ai un peu essayé de regarder la fonction 'explore', la première chose que je note c'est que tu mélanges dans la même fonction du code itératif (boucle while) et du code récursif. Comme j'ai essayé de l'expliquer, il s'agit là de deux façons de penser (algorithmie) fondamentalement différentes et vouloir mixer ces deux approches ne t'aide certainement pas à résoudre ton problème. Un bon point, tu scindes ton code ton code en plusieurs fonctions, ce qui permet de résoudre les problèmes séparément à condition d'éviter les effets de bord, pour ça il suffit d'utiliser des fonctions "pures" (fonctions qui prennent des arguments et retourne une valeur sans interférer sur les variables de la fonction parent). Ceci permet de construire et tester chaque sous fonction en dehors de l'environnement du programme (tests unitaires). Par exemple, dans ton cas la fonction 'explore' qui doit traiter une liste spécifique du programme devrait pouvoir être testée et déboguée séparément avec n'importe quelle liste similaire. Avant d'ouvrir la moindre parenthèses dans l'éditeur Visual LISP, essaye de poser par écrit ce que tu cherches à faire de la manière la plus simple et la plus explicite possible : ce dont tu dispose au départ et ce à quoi tu veux arriver. Parfois c'est suffisant pour être traduit directement en code, surtout quand on a compris le fonctionnements des fonctions d'ordre supérieur (apply, mapcar, vl-remove-if, etc.) qui permettent d'écrire du code déclaratif dans lequel on écrit ce qu'on veut faire (l'intention) plutôt que la façon dont il faut le faire (la manière). Sinon, il faut que tu envisages (toujours sans écrire la moindre ligne de code) comment tu peux y arriver au résultat souhaité à partir des données initiales en utilisant uniquement de la logique binaire (si..., ...alors, ...sinon), c'est ce qu'on appelle l'algorithme (souvent différents algorithmes permette de résoudre le même problème). our ce faire, tu peux t'aider à le formaliser en utilisant un logigramme. Quand tu as réussi à décrire ton algorithme de façon claire, le code coule de source.
-
Ta question est confuse. As-tu une erreur ? Si oui où ? Sinon c'est quoi le problème ? De plus ton code n'est pas très bien présentation / formatage et ça ne donne pas très envie de se plonger dedans. Commence par ça : d'un côté tu soignes un peu la présentation code pour qu'il soit plus lisible, mieux organisé (si, si, ça compte) et d'un autre tu essaye de formuler clairement ton problème, en général quand on y arrive, on a pratiquement résolu le problème.
-
Comme dit Denis, il faut supprimer l'ancien fichier, je ne vois pas d'autre moyen. À ma connaissance on ne peut pas renommer un fichier en cours d'utilisation (ce qui est plutôt une bonne chose).
-
Salut, Enregistrer sous (SAUVNOM ou _SAVEAS) ?
-
On sort d'une fonction récursive quand on atteint la condition d'arrêt (la liste est vide), les appels récursifs devant faire tendre vers cette condition. Un exemple simple, pour compter le nombre d'éléments d'une liste (ce que fait la fonction length). Algorithme récursif: Le nombre d'éléments d'une liste est égal à : - 0 si la liste est vide (condition d'arrêt) - 1 plus le nombre d'éléments de la liste sans le premier élément (appel récursif) Ce qui se traduit simplement en code par : (defun count (l) (if (null l) 0 (1+ (count (cdr l))) ) ) Comment ça marche. Jusqu'à atteindre la condition d'arrêt, c'est la phase d'"empilement" (on empile les appels récursif) (count '("a" "b" "c" "d")) (1+ (count '("b" "c" "d"))) (1+ (1+ (count '("c" "d")))) (1+ (1+ (1+ (count '("d"))))) (1+ (1+ (1+ (1+ (count '()))))) Puis c'est la phase de "dépilement" (évaluation de chaque expression de la pile) (1+ (1+ (1+ (1+ 0)))) (1+ (1+ (1+ 1))) (1+ (1+ 2)) (1+ 3) 4 Excepté dans certains cas, comme le traitement des arborescences (un dossier peut contenir des fichiers et des dossiers), un algorithme récursif peut être remplacé par un algorithme impératif qui au lieu d'utiliser des appels de fonction, utilise des changements d'états. Là encore, il faut définir une condition d'arrêt pour sortir de la boucle et les changements d'état doivent faire tendre vers la condition d'arrêt. Algorithme impératif (itératif) Pour compter les éléments d'une liste : - on initalise un compteur à 0 - et tant que la liste n'est pas vide (condition d'arrêt), - on ajoute 1 au compteur (changement d'état) - on supprime le premier élément de la liste (changement d'état) - on renvoie la valeur du compteur Ce qui se traduit en code par : (defun count (l / i) (setq i 0) (while l (setq i (1+ i) l (cdr l) ) ) i )
