Grrr Posted August 13, 2016 Posted August 13, 2016 (edited) Hi guys, I was trying to find the shortest way to store and reset a list of system variables. However I'm not a list manipulation guru so I need some help with the mapcar and lambda functions: (defun C:test ( / vars ) ; declare the list of variable names where each item is: (var-name-X new-var-val-X): (setq vars '(("FILLETRAD" 10) ("CLIPROMPTLINES" 1) ("OSMODE" 0) ("CMDECHO" 0))) ; this should reconstruct the list where each item is: (var-name-X old-varval-X new-var-val-X)): (setq vars (mapcar '(lambda (x) (list (car x) (getvar (car x)) (cadr x)) vars))) ; set the new values: (mapcar '(lambda (x) (setvar (car x) (caddr x)) vars)) ; perform var-check: (foreach x vars (princ (strcat (car x) " with value: " (getvar (car x)))) ) (alert "\nThe main function starts!") ; restore the variable values: (mapcar '(lambda (x) (setvar (car x) (cadr x)) vars)) ; perform var-check: (foreach x vars (princ (strcat (car x) " with value: " (getvar (car x)))) ) (princ) ); defun The goal is to set only 1 quote named "vars" instead a bunch of quotes for each system variable. So we could all benefit from it In other words (some tests copied from the visual lisp console): _$ ; declare the list of variable names "vars" where each item is: (var-name-X new-var-val-X): (setq vars '(("FILLETRAD" 10) ("CLIPROMPTLINES" 1) ("OSMODE" 0) ("CMDECHO" 0))) (("FILLETRAD" 10) ("CLIPROMPTLINES" 1) ("OSMODE" 0) ("CMDECHO" 0)) _$ ; this should reconstruct the list to "nvars" where each item is: (var-name-X old-varval-X new-var-val-X)): (setq nvars (list)) nil _$ _$ (foreach itm vars (if (not (member (car itm) (mapcar 'car nvars))) (setq nvars (cons (list (car itm) (getvar (car itm)) (cadr itm)) nvars)) ) ) (("CMDECHO" 1 0) ("OSMODE" 15359 0) ("CLIPROMPTLINES" 4 1) ("FILLETRAD" 52.0 10)) _$ (setq nvars (reverse nvars)) (("FILLETRAD" 52.0 10) ("CLIPROMPTLINES" 4 1) ("OSMODE" 15359 0) ("CMDECHO" 1 0)) _$ ; set the new values: (foreach itm nvars (setvar (car itm) (caddr itm)) (princ (strcat "\n" (car itm) " : " (rtos (getvar (car itm))))) ) FILLETRAD : 10.0000 CLIPROMPTLINES : 1.0000 OSMODE : 0.0000 CMDECHO : 0.0000"\nCMDECHO : 0.0000" _$ (alert "\nThe main function starts!") nil _$ ; restore the variable values: (foreach itm nvars (setvar (car itm) (cadr itm)) (princ (strcat "\n" (car itm) " : " (rtos (getvar (car itm))))) ) FILLETRAD : 52.0000 CLIPROMPTLINES : 4.0000 OSMODE : 15359.0000 CMDECHO : 1.0000"\nCMDECHO : 1.0000" _$ But here I used 2 quotes "vars" and "nvars" - my question is is it possible to shorten it to only one "vars" and perhaps some overwriting (using mapcar/lambda instead of my newbie foreach approach). Edited August 13, 2016 by Grrr Quote
BIGAL Posted August 14, 2016 Posted August 14, 2016 (edited) Just me make the list a bit simpler (list "FILLETRAD" 10 "CLIPROMPTLINES" 1 "OSMODE" 0 "CMDECHO" 0) Then just use a repeat function which is the length/2, nth x is the variable name nth x+1 is the value. If you want you can make two lists and call a single defun passing the correct list name. I get lost in lamba's sometimes so not sure how much shorter the defun would become or would be any real gain as its instant now. (defun c:myvars ( / vars) (setq vars (list "FILLETRAD" 10 "CLIPROMPTLINES" 1 "OSMODE" 0 "CMDECHO" 0)) (myvars vars) ) (defun C:myvarsu ( / varsu ) (setq varsu (list "FILLETRAD" 10 "CLIPROMPTLINES" 1 "OSMODE" 47 "CMDECHO" 1)) (myvars varsu) ) (defun myvars ( vars / x) (setq x 0) (repeat (/ (length vars) 2) (setq sysvar (nth x vars)) (setq sysval (nth (+ x 1) vars)) (command sysvar sysval) (setq x (+ x 2)) ) ) Edited August 14, 2016 by BIGAL Quote
David Bethel Posted August 14, 2016 Posted August 14, 2016 I use dotted pairs ;++++++++++++ Set Modes ++++++++++++++++++++++++++++++++++ (defun nw_smd () (setq nw_var '(("CMDECHO" . 0) ("MENUECHO" . 0) ("MENUCTL" . 0) ("MACROTRACE" . 0) ("OSMODE" . 0) ("SORTENTS" . 119) ("LUPREC" . 2) ("MODEMACRO" . ".") ("BLIPMODE" . 0) ("EXPERT" . 5) ("SNAPMODE" . 1) ("PLINEWID" . 0) ("ORTHOMODE" . 1) ("GRIDMODE" . 0) ("ELEVATION" . 0) ("THICKNESS" . 0) ("FILEDIA" . 0) ("FILLMODE" . 0) ("SPLFRAME" . 0) ("UNITMODE" . 0) ("TEXTEVAL" . 0) ("ATTDIA" . 0) ("AFLAGS" . 0) ("ATTREQ" . 1) ("ATTMODE" . 1) ("UCSICON" . 1) ("HIGHLIGHT" . 1) ("REGENMODE" . 1) ("COORDS" . 2) ("DRAGMODE" . 2) ("DIMZIN" . ("PDMODE" . 0) ("SNAPUNIT" . (1 1)) ("CECOLOR" . "BYLAYER") ("CELTYPE" . "BYLAYER"))) (foreach v nw_var (and (getvar (car v)) (setq nw_rst (cons (cons (car v) (getvar (car v))) nw_rst)) (setvar (car v) (cdr v)))) (princ)) ;++++++++++++ Return Modes +++++++++++++++++++++++++++++++ (defun nw_rmd () (foreach v nw_rst (setvar (car v) (cdr v))) (prin1)) I like the organized feel. -David Quote
Lee Mac Posted August 14, 2016 Posted August 14, 2016 The goal is to set only 1 quote named "vars" instead a bunch of quotes for each system variable. So we could all benefit from it But here I used 2 quotes "vars" and "nvars" - my question is is it possible to shorten it to only one "vars" Personally, I would advise against overwriting your 'vars' variable when storing the existing system variable values, as you will also need to include an expression within a local error handler to reset the system variables if an error is encountered. Therefore, by using the same variable name, you would need to rely on testing for a different list structure in order to determine whether the 'vars' variable holds the stored system variable values or the new values (as the error may be encountered before or after the existing values are stored). I would instead suggest using a separate variable to store the existing values, for example: (defun c:test ( / *error* vals vars ) (defun *error* ( msg ) (foreach val vals (if val (apply 'setvar val))) (princ) ) (setq vars '( (filletrad 10) (clipromptlines 1) (osmode 0) (cmdecho 0) ) ) (setq vals (mapcar '(lambda ( x / v ) (if (setq v (getvar (car x))) (progn(apply 'setvar x) (list (car x) v)) ) ) vars ) ) ;; < do stuff > (foreach val vals (if val (apply 'setvar val))) (princ) ) Though, sometimes you don't want to change the values of all system variables in the list at the same time, and so the following approach may be more appropriate: (defun c:test ( / *error* vals vars ) (defun *error* ( msg ) (mapcar '(lambda ( a b ) (if b (setvar a b))) vars vals) (princ) ) (setq vars '(filletrad clipromptlines osmode cmdecho) vals (mapcar 'getvar vars) ) ;; Change system variables as appropriate using separate setvar expressions (mapcar '(lambda ( a b ) (if b (setvar a b))) vars vals) (princ) ) Note that the above examples also test whether the getvar expression returns a non-nil value when obtaining the existing system variable values, as not all system variables are available in all versions of AutoCAD. ...using mapcar/lambda instead of my newbie foreach approach. I must say that there is nothing 'newbie' about using foreach; there are many solutions in which foreach is the most appropriate function for the task, for example: if you are iterating over items in a list and you are not using the values returned when processing the items, foreach is more appropriate than mapcar. Quote
Grrr Posted August 14, 2016 Author Posted August 14, 2016 Thanks for the help guys! Lee, I revised your suggestions (thank you for posting them and your oppinion about this subject). I did some modifications and tests from the codes you provided and ended up with this (commented version): [b][color=BLACK]([/color][/b]defun c:test [b][color=FUCHSIA]([/color][/b] / *error* vars [b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]defun *error* [b][color=NAVY]([/color][/b] msg [b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]"\n>>> An error occured ! <<<"[/color][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]"\n>>>Restore the variables: "[/color][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]foreach x vars [b][color=MAROON]([/color][/b]if [b][color=GREEN]([/color][/b]getvar [b][color=BLUE]([/color][/b]car x[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b] [b][color=GREEN]([/color][/b]setvar [b][color=BLUE]([/color][/b]car x[b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]caddr x[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [color=#8b4513]; assign original values[/color] [b][color=NAVY]([/color][/b]foreach x [b][color=MAROON]([/color][/b]mapcar 'car vars[b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]prin1 x[b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]princ [color=#2f4f4f]" : "[/color][b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]prin1 [b][color=GREEN]([/color][/b]getvar x[b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [color=#8b4513]; to perform print check[/color] [b][color=NAVY]([/color][/b]princ[b][color=NAVY])[/color][/b] [b][color=FUCHSIA])[/color][/b] [color=#8b4513]; here the user constructs an assoc list, where each item contains [b][color=FUCHSIA]([/color][/b]<variable name> <new variable value>[b][color=FUCHSIA])[/color][/b]:[/color] [b][color=FUCHSIA]([/color][/b]setq vars [color=#8b4513]; [b][color=NAVY]([/color][/b]<var name> <new value>[b][color=NAVY])[/color][/b][/color] '[b][color=NAVY]([/color][/b] [b][color=MAROON]([/color][/b]filletrad 10[b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]clipromptlines 1[b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]osmode 0[b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]cmdecho 0[b][color=MAROON])[/color][/b] [b][color=NAVY])[/color][/b] [b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n>>>The original variables: "[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]foreach x [b][color=NAVY]([/color][/b]mapcar 'car vars[b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]prin1 x[b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]" : "[/color][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]prin1 [b][color=MAROON]([/color][/b]getvar x[b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=NAVY])[/color][/b][b][color=FUCHSIA])[/color][/b] [color=#8b4513]; to perform print check[/color] [b][color=FUCHSIA]([/color][/b]if [b][color=NAVY]([/color][/b]not tempvars[b][color=NAVY])[/color][/b] [color=#8b4513]; check if there isn't such global variable[/color] [b][color=NAVY]([/color][/b]if [b][color=MAROON]([/color][/b]setq tempvars [color=#8b4513]; temporary assign the list to that variable[/color] [b][color=GREEN]([/color][/b]mapcar '[b][color=BLUE]([/color][/b]lambda [b][color=RED]([/color][/b] x / v [b][color=RED])[/color][/b] [b][color=RED]([/color][/b]if [b][color=PURPLE]([/color][/b]setq v [b][color=TEAL]([/color][/b]getvar [b][color=OLIVE]([/color][/b]car x[b][color=OLIVE])[/color][/b][b][color=TEAL])[/color][/b][b][color=PURPLE])[/color][/b] [b][color=PURPLE]([/color][/b]list [b][color=TEAL]([/color][/b]car x[b][color=TEAL])[/color][/b] [b][color=TEAL]([/color][/b]cadr x[b][color=TEAL])[/color][/b] v[b][color=PURPLE])[/color][/b][color=#8b4513]; [b][color=PURPLE]([/color][/b]<var name> <new value> <original value>[b][color=PURPLE])[/color][/b][/color] [b][color=RED])[/color][/b] [b][color=BLUE])[/color][/b] vars [b][color=GREEN])[/color][/b] [b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]progn [b][color=GREEN]([/color][/b]setq vars tempvars[b][color=GREEN])[/color][/b] [color=#8b4513]; re-quote the [color=#2f4f4f]"vars"[/color] list[/color] [b][color=GREEN]([/color][/b]setq tempvars nil[b][color=GREEN])[/color][/b] [color=#8b4513]; remove that global variable[/color] [b][color=MAROON])[/color][/b] [b][color=NAVY])[/color][/b] [b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n>>> The code started ! <<<"[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n>>> Changing the variables: "[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]foreach x vars [b][color=NAVY]([/color][/b]if [b][color=MAROON]([/color][/b]getvar [b][color=GREEN]([/color][/b]car x[b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]setvar [b][color=GREEN]([/color][/b]car x[b][color=GREEN])[/color][/b] [b][color=GREEN]([/color][/b]cadr x[b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b][b][color=FUCHSIA])[/color][/b] [color=#8b4513]; assign new values[/color] [b][color=FUCHSIA]([/color][/b]foreach x [b][color=NAVY]([/color][/b]mapcar 'car vars[b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]prin1 x[b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]" : "[/color][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]prin1 [b][color=MAROON]([/color][/b]getvar x[b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=NAVY])[/color][/b][b][color=FUCHSIA])[/color][/b] [color=#8b4513]; to perform print check[/color] [b][color=FUCHSIA]([/color][/b]getstring t [color=#2f4f4f]"\nInput something: \n"[/color][b][color=FUCHSIA])[/color][/b][color=#8b4513]; < do stuff >[/color] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n>>>Restore the variables: "[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]foreach x vars [b][color=NAVY]([/color][/b]if [b][color=MAROON]([/color][/b]getvar [b][color=GREEN]([/color][/b]car x[b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]setvar [b][color=GREEN]([/color][/b]car x[b][color=GREEN])[/color][/b] [b][color=GREEN]([/color][/b]caddr x[b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b][b][color=FUCHSIA])[/color][/b] [color=#8b4513]; assign original values[/color] [b][color=FUCHSIA]([/color][/b]foreach x [b][color=NAVY]([/color][/b]mapcar 'car vars[b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]prin1 x[b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]" : "[/color][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]prin1 [b][color=MAROON]([/color][/b]getvar x[b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]princ [color=#2f4f4f]"\n"[/color][b][color=NAVY])[/color][/b][b][color=FUCHSIA])[/color][/b] [color=#8b4513]; to perform print check[/color] [b][color=FUCHSIA]([/color][/b]princ [color=#2f4f4f]"\n>>> The code ended ! <<<"[/color][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]princ[b][color=FUCHSIA])[/color][/b] [b][color=BLACK])[/color][/b][color=#8b4513];defun [/color] Where the printed results in the console are: -user successifuly ends the routine: Command: TEST >>>The original variables: FILLETRAD : 245.0 CLIPROMPTLINES : 4 OSMODE : 15359 CMDECHO : 1 >>> The code started ! <<< >>> Changing the variables: FILLETRAD : 10.0 CLIPROMPTLINES : 1 OSMODE : 0 CMDECHO : 0 Input something: some text >>>Restore the variables: FILLETRAD : 245.0 CLIPROMPTLINES : 4 OSMODE : 15359 CMDECHO : 1 >>> The code ended ! <<< Command: -user ends the routine with an error: Command: TEST >>>The original variables: FILLETRAD : 245.0 CLIPROMPTLINES : 4 OSMODE : 15359 CMDECHO : 1 >>> The code started ! <<< >>> Changing the variables: FILLETRAD : 10.0 CLIPROMPTLINES : 1 OSMODE : 0 CMDECHO : 0 Input something: *Cancel* >>> An error occured ! <<< >>>Restore the variables: FILLETRAD : 245.0 CLIPROMPTLINES : 4 OSMODE : 15359 CMDECHO : 1 Command: By removing the printchecks and the comments - the above code I posted, could be shortened up to: (defun c:test ( / *error* vars ) (defun *error* ( msg ) (foreach x vars (if (getvar (car x)) (setvar (car x) (caddr x)))) ; assign original values (princ) ) ; here the user constructs an assoc list, where each item contains (<variable name> <new variable value>): (setq vars ; (<var name> <new value>) '( (filletrad 10) (clipromptlines 1) (osmode 0) (cmdecho 0) ) ) (if (not tempvars) ; check if there isn't such global variable (if (setq tempvars (mapcar '(lambda ( x / v ) (if (setq v (getvar (car x))) (list (car x) (cadr x) v))) vars)); (<var name> <new value> <original value>) (setq vars tempvars tempvars nil) ) ) (foreach x vars (if (getvar (car x)) (setvar (car x) (cadr x)))) ; assign new values (getstring t "\nInput something: \n"); < do stuff > (foreach x vars (if (getvar (car x)) (setvar (car x) (caddr x)))) ; assign original values (princ) );defun Quote
Lee Mac Posted August 14, 2016 Posted August 14, 2016 To each their own, but personally I really don't see the need for juggling the variables just so that you can reuse the 'vars' variable - this also relies on the 'vars' variable being immediately redefined with no errors encountered in the process, else the foreach expression within the local error handler will error. Quote
Grrr Posted August 15, 2016 Author Posted August 15, 2016 Thanks alot Lee! You offered several cases for someone to use for their codes - and more importantly: in the shortest way possible. Basically you are everywhere in this LISP world... (atleast I know when something clever comes up in someone's code - no wonder you were the guy to figure it out first or atleast have been a part from it). Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.