Concatenate text with variable for in list

Concatenate text with variable for in list

Anonymous
Not applicable
4,897 Views
35 Replies
Message 1 of 36

Concatenate text with variable for in list

Anonymous
Not applicable

How can I create a list that concatenates text and an item from a list?

 

(defun LM:changevis (lst1 lst2 / idx lst obj sel vis )
    (setq lst
       '(  ;i know i need to remove this ' so that i can evaluate below
            strcat("\"PANEL SIZE\"  . \" (nth 1 lst2))    ;SET 2nd ITEM OF lst 1 to 2nd item of lst2
            ("BOM1" . (nth 2 lst2))    ;SET 3rd ITEM OF lst 1 to 3rd item of lst2
	    ("BOM2"  . (nth 3 lst2))    ;SET 4th ITEM OF lst 1 to 4th item of lst2

        )
    )

 

Alternatively, if i can loop thru each item in ls1 and create a list ("lst1 item 2" . "lst2 item 2") that would be better. The original code looked like this: 

(defun LM:changevis ( / idx lst obj sel vis )
    (setq lst
       '( 
            ("BOM1" . "ITEM1")
	    ("BOM2"  . "ITEM2")
            ("BOM3" . "ITEM3")
        )
    )

I was hoping to take it and pass 2 lists (lst1 lst2) and rewrite the section of code for concatenating the strings to be the values of the lists instead. I'm sure there's a way to loop this, but i'm more of a vba guy.

0 Likes
Accepted solutions (1)
4,898 Views
35 Replies
Replies (35)
Message 2 of 36

ВeekeeCZ
Consultant
Consultant

(mapcar 'strcat lst1 lst2)

 

(setq lst1 '("1" "2"))

(setq lst2 '("a" "b"))

>> ("1a" "2b")

 

OR

(setq lst '(("BOM1" . "ITEM1")
	    ("BOM2"  . "ITEM2")
            ("BOM3" . "ITEM3")))

(setq lst (mapcar '(lambda (x) (strcat (car x) (cdr x))) lst)))

>> ("BOM1ITEM1" "BOM2ITEM2" "BOM3ITEM3")
 
0 Likes
Message 3 of 36

ВeekeeCZ
Consultant
Consultant

Or, if you not versed with mapcar use foreach

 

(foreach i lst
  (setq ls2 (cons (strcat (car i) (cdr i)) ls2)))
(reverse ls2)

 

 
0 Likes
Message 4 of 36

Anonymous
Not applicable

ok. that is giving me this error: 

; error: bad argument type: stringp 30.0

 

I'm sure it's due to the way the list is created originally. It's created using a lisp that reads from excel a range. In excel the range is defined as text, but the lisp function is I guess seeing the numbers as numbers? Any idea how to resolve this? Here's the lisp code I obtained from another forum post:

 

(defun getCells (fileName sheetName cellName / xl workbook sheet range cellValue)
   (setq xl(vlax-get-or-create-object "Excel.Application"))
   (vla-put-visible xl :vlax-false)
   (vlax-put-property xl 'DisplayAlerts :vlax-false)
   (setq workbook (vl-catch-all-apply 'vla-open (list (vlax-get-property xl "WorkBooks") fileName)))
   (setq sheet (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property workbook "Sheets") "Item" sheetName)))
   (vlax-invoke-method sheet "Activate")
   (setq range (vlax-get-property (vlax-get-property sheet 'Cells) "Range" cellName))
   (setq cellValue(vlax-variant-value (vlax-get-property range 'Value2)))
   (vl-catch-all-apply 'vlax-invoke-method (list workbook "Close"))
   (vl-catch-all-apply 'vlax-invoke-method (list xl "Quit"))
   (if (not (vlax-object-released-p range))(progn(vlax-release-object range)(setq range nil)))
   (if (not (vlax-object-released-p sheet))(progn(vlax-release-object sheet)(setq sheet nil)))
   (if (not (vlax-object-released-p workbook))(progn(vlax-release-object workbook)(setq workbook nil)))
   (if (not (vlax-object-released-p xl))(progn(vlax-release-object xl)(setq xl nil)))    
   (if(= 'safearray (type cellValue))
     (progn
       (setq tempCellValue(vlax-safearray->list cellValue))
       (setq cellValue(list))
       (if(= (length tempCellValue) 1)
         (progn
           (foreach a tempCellValue
             (if(= (type a) 'LIST)
               (progn
                 (foreach b a
                   (if(= (type b) 'LIST)
                     (setq cellValue(append cellValue (list (vlax-variant-value (car b)))))
                     (setq cellValue(append cellValue (list (vlax-variant-value b))))
                   )
                 )
               )
               (setq cellValue(append cellValue (list (vlax-variant-value a))))
             )
           )
         )
         (progn
           (foreach a tempCellValue
             (setq tmpList(list))
             (foreach b a
               (setq tmp(vlax-variant-value b))
               (setq tmpList(append tmpList (list tmp)))
             )
             (setq cellValue(append cellValue tmpList))
           )
         )
       )
     )
   )
   cellValue
 )

And here is the code that calls the above function and creates the list from excel:

(defun c:readexcel ()							
  (vl-load-com)
  (setq fname "C:\\foldername\\workbook.xls"
        shname "sheet1"
        range1  "A1:A14"
        range2  "B1:B14"
  )
  (setq lst1 (getcells fname shname range1))
  (setq lst2 (getcells fname shname range2))
 (LM:changevis lst1 lst2)
)  

 

0 Likes
Message 5 of 36

Anonymous
Not applicable

Here's the updated changevis function  (renamed from an LM function that I found somewhere:

 

(defun LM:changevis (lst1 lst2 / idx lst obj sel vis )
    (setq lst
       (
	(foreach i lst
  		(setq ls2 (cons (strcat (car i) ( . ) (cdr i)) ls2)))
	(reverse ls2)	
        )
    )

I added the ( . ) since it appears the list needs to be separated that way from the previous code. But I'm getting this error still:

; error: bad argument type: stringp 30.0

 

0 Likes
Message 6 of 36

ВeekeeCZ
Consultant
Consultant

Use your code and print the values.

 

(print (getcells fname shname range1))

(print (getcells fname shname range2))

 

Then write a line of values in the desired format.

0 Likes
Message 7 of 36

Anonymous
Not applicable

Can you explain what you mean by: "Then write a line of values in the desired format."? Also, what's the point of the printing the values here? Just trying to learn 🙂 Thank you.

0 Likes
Message 8 of 36

ВeekeeCZ
Consultant
Consultant

Nevermind. Post the xls please.

0 Likes
Message 9 of 36

Anonymous
Not applicable

OK.

0 Likes
Message 10 of 36

ВeekeeCZ
Consultant
Consultant

Good, that's game changer. But still halfway.

Now, what you need the result list for? What's your goal?

 

I'm thinking that all you need is this:

(mapcar 'cons lst1 lst2)
0 Likes
Message 11 of 36

Anonymous
Not applicable

The result list will be used in this code to select a dynamic block visibility state.

(defun LM:changevis (lst1 lst2 / idx lst obj sel vis )
    (setq lst
       (
	(foreach i lst
  		(setq ls2 (cons (strcat (car i) ( . ) (cdr i)) ls2)))
	(reverse ls2)
    (if
        (setq sel
            (ssget "_X"
                (append
                   '(
                        (000 . "INSERT")
                        (-04 . "<OR")
                        (002 . "`*U*")
                    )
                    (mapcar '(lambda ( x ) (cons 2 (car x))) lst)
                   '(
                        (-004 . "OR>")
                        (410 . "Model")
                    )
                )
            )
        )
        (repeat (setq idx (sslength sel))
            (if (setq idx (1- idx)
                      obj (vlax-ename->vla-object (ssname sel idx))
                      vis (cdr (assoc (strcase (LM:blockname obj)) lst))
                )
                (LM:SetVisibilityState obj vis)
            )
        )
    )
    (princ)
)

 You'll see the new code at the top. 

0 Likes
Message 12 of 36

ВeekeeCZ
Consultant
Consultant

Ok, add Lee's subs and try.

 

(vl-load-com)

(defun c:BOMSet ( / sel getCells readexcel sel idx obj vis)
  
  (defun getCells (fileName sheetName cellName / xl workbook sheet range cellValue)
    (setq xl(vlax-get-or-create-object "Excel.Application"))
    (vla-put-visible xl :vlax-false)
    (vlax-put-property xl 'DisplayAlerts :vlax-false)
    (setq workbook (vl-catch-all-apply 'vla-open (list (vlax-get-property xl "WorkBooks") fileName)))
    (setq sheet (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property workbook "Sheets") "Item" sheetName)))
    (vlax-invoke-method sheet "Activate")
    (setq range (vlax-get-property (vlax-get-property sheet 'Cells) "Range" cellName))
    (setq cellValue(vlax-variant-value (vlax-get-property range 'Value2)))
    (vl-catch-all-apply 'vlax-invoke-method (list workbook "Close"))
    (vl-catch-all-apply 'vlax-invoke-method (list xl "Quit"))
    (if (not (vlax-object-released-p range))(progn(vlax-release-object range)(setq range nil)))
    (if (not (vlax-object-released-p sheet))(progn(vlax-release-object sheet)(setq sheet nil)))
    (if (not (vlax-object-released-p workbook))(progn(vlax-release-object workbook)(setq workbook nil)))
    (if (not (vlax-object-released-p xl))(progn(vlax-release-object xl)(setq xl nil)))
    (if(= 'safearray (type cellValue))
      (progn
	(setq tempCellValue(vlax-safearray->list cellValue))
	(setq cellValue(list))
	(if(= (length tempCellValue) 1)
	  (progn
	    (foreach a tempCellValue
	      (if(= (type a) 'LIST)
		(progn
		  (foreach b a
		    (if(= (type b) 'LIST)
		      (setq cellValue(append cellValue (list (vlax-variant-value (car b)))))
		      (setq cellValue(append cellValue (list (vlax-variant-value b)))))))
		(setq cellValue(append cellValue (list (vlax-variant-value a)))))))
	  (progn
	    (foreach a tempCellValue
	      (setq tmpList(list))
	      (foreach b a
		(setq tmp(vlax-variant-value b))
		(setq tmpList(append tmpList (list tmp))))
	      (setq cellValue(append cellValue tmpList)))))))
    cellValue
    )
  
  (defun readexcel ( / fname sjname )
    (setq fname "C:\\foldername\\workbook.xls"
	  shname "sheet1"
	  range1  "A1:A14"
	  range2  "B1:B14"
	  )
    (if (and (setq lst1 (getcells fname shname range1))
	     (setq lst2 (getcells fname shname range2)))
      
      (mapcar 'cons lst1 lst2)))
  
  ; ------------------------------------------------------------------------
  
  
  (if (and (setq sel (ssget "_X" (append '((000 . "INSERT")
					   (-04 . "<OR")
					   (002 . "`*U*"))
					 (mapcar '(lambda ( x ) (cons 2 (car x))) lst)
					 '((-004 . "OR>")
					   (410 . "Model")))))
	   (setq lst (readexcel))
	   )
    (repeat (setq idx (sslength sel))
      (if (setq idx (1- idx)
		obj (vlax-ename->vla-object (ssname sel idx))
		vis (cdr (assoc (strcase (LM:blockname obj)) lst))
		)
	(LM:SetVisibilityState obj vis))))
  (princ)
  )

 

0 Likes
Message 13 of 36

ВeekeeCZ
Consultant
Consultant

Ok, some explanation.

 

You never needed concatenate. That's just for strings. You needed to build a list using list and cons functions.

 

If you work with constancies, you can type manually: (setq lst '(("BOM1" . 30) ("BOM2" . "Test"))) (no evaluation needed)

But if you have those values in some variables, just list and cons. Because those variables has to be evaluated.

 

(setq b1 "BOM1")

(setq v1 30)

(setq v2 "Test")

(setq lst (list (cons b1 v1) (cons "BOM2" v2)))

>> '(("BOM1" . 30) ("BOM2" . "Test"))

 

HTH Bedtime here.

 

0 Likes
Message 14 of 36

Anonymous
Not applicable

Thank you for your help. The (mapcar 'cons lst1 lst2) is perfect, what does 'cons exactly do. I thought the ' made the script not evaluate?

 

Also, the code almost works. It only does the 1st item in the list and doesn't cycle thru each item in the list. I was expecting this piece of code below to loop thru and call LM:SetVisilityState on each item in the list.

 

  (if (and (setq sel (ssget "_X" (append '((000 . "INSERT")
					   (-04 . "<OR")
					   (002 . "`*U*"))
					 (mapcar '(lambda ( x ) (cons 2 (car x))) lst)
					 '((-004 . "OR>")
					   (410 . "Model")))))
	   (setq lst (readexcel))
	   )
    (repeat (setq idx (sslength sel))
      (if (setq idx (1- idx)
		obj (vlax-ename->vla-object (ssname sel idx))
		vis (cdr (assoc (strcase (LM:blockname obj)) lst))
		)
	(LM:SetVisibilityState obj vis))))
  (princ)
  )

 

Am I misunderstanding? If not, how to fix it so it loops?

 

0 Likes
Message 15 of 36

ВeekeeCZ
Consultant
Consultant

I'm thinking that all visibility states has to be strings. So try this one instead...

(mapcar 'cons lst1 (mapcar 'vl-princ-to-string lst2))

 

If still not working, post some sample dwg with couple of blocks to test.

 

Mapcar is the one to be evaluated. Cons is just quoted. But if you don't like it, you can use function.

(mapcar (function cons) lst1 lst2). But to be fair, these mapcar/lambda things... are from quite advanced lessons.

0 Likes
Message 16 of 36

Anonymous
Not applicable

I should have mentioned that if can run this code multiple times on the same drawing and each time it will update the next dynamic block on the drawing, so the original code may be correct, it just doesn't seem to be looping to the next block and rechecking the list.

0 Likes
Message 17 of 36

Anonymous
Not applicable

Also the new command gives me this error: error: malformed list on input when I use that.

0 Likes
Message 18 of 36

Anonymous
Not applicable

I don't think it has anything to do with the string command you suggested. Like I said, if I run it a second time, it gets another block and changes it. It has to do with the looping here:

 

  (defun readexcel ( / fname sjname )
    (setq fname "C:\\foldername\\workbook.xls"
	  shname "sheet1"
	  range1  "A1:A14"
	  range2  "B1:B14"
;  )
  )
    (if (and (setq lst1 (getcells fname shname range1))
	     (setq lst2 (getcells fname shname range2)))
      
      ;(mapcar 'cons lst1 lst2)))
	  (mapcar 'cons lst1 (mapcar 'vl-princ-to-string lst2))
  
  ; ------------------------------------------------------------------------
  
  (if (and (setq sel (ssget "_X" (append '((000 . "INSERT")
					   (-04 . "<OR")
					   (002 . "`*U*"))
					 (mapcar '(lambda ( x ) (cons 2 (car x))) lst)
					 '((-004 . "OR>")
					   (410 . "Model")))))
	   (setq lst (readexcel))
	   )
    (repeat (setq idx (sslength sel))
      (if (setq idx (1- idx)
		obj (vlax-ename->vla-object (ssname sel idx))
		vis (cdr (assoc (strcase (LM:blockname obj)) lst))
		)
	(LM:SetVisibilityState obj vis))))
  (princ)
  )

For each dynamic block in the drawing (match lst1 item), then set to visibility state (lst2 item). It works, but it just doesn't do each block unless i run the code again. It only does 1 for each run. 

 

 

0 Likes
Message 19 of 36

CodeDing
Advisor
Advisor

@Anonymous ,

 

My $0.02...

 

IF all of your cells that you are getting from excel, are to be used as TEXT items only... then I would just take this line from your original code...

(setq cellValue (vlax-variant-value (vlax-get-property range 'Value2)))

...and change it to this...

(setq cellValue (vlax-variant-value (vlax-get-property range 'Text)))

 

I have not read this thread in its entirety, but based on the first couple responses, this may prevent some snags that are holding you up. Or... it could create another whirlwind of mess.

 

Best,

~DD

Message 20 of 36

Anonymous
Not applicable

I do not think it is an issue with string/text/format. I made the change you suggested and still get the same result which is only 1 dynamic block's visibility is updated. The only difference is, when i make your suggested change, not even consecutive runs will update another block. With the original code, added for convenience below, i can run the code a second or third, etc time and 1 at a time other dynamic blocks are updated. it's almost like it stops after making a change to 1 dynamic block. SO since it set 1 to match lst2 the 1st time, it can skip that one on the next run.

;; Block Name  -  Lee Mac
;; Returns the true (effective) name of a supplied block reference
                        
(defun LM:blockname ( obj )
    (if (vlax-property-available-p obj 'effectivename)
        (defun LM:blockname ( obj ) (vla-get-effectivename obj))
        (defun LM:blockname ( obj ) (vla-get-name obj))
    )
    (LM:blockname obj)
)

;; Set Dynamic Block Visibility State  -  Lee Mac
;; Sets the Visibility Parameter of a Dynamic Block (if present) to a specific value (if allowed)
;; blk - [vla] VLA Dynamic Block Reference object
;; val - [str] Visibility State Parameter value
;; Returns: [str] New value of Visibility Parameter, else nil

(defun LM:SetVisibilityState ( blk val / vis )
    (if
        (and
            (setq vis (LM:getvisibilityparametername blk))
            (member (strcase val) (mapcar 'strcase (LM:getdynpropallowedvalues blk vis)))
        )
        (LM:setdynpropvalue blk vis val)
    )
)

;; Set Dynamic Block Property Value  -  Lee Mac
;; Modifies the value of a Dynamic Block property (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)
;; val - [any] New value for property
;; Returns: [any] New value if successful, else nil

(defun LM:setdynpropvalue ( blk prp val )
    (setq prp (strcase prp))
    (vl-some
       '(lambda ( x )
            (if (= prp (strcase (vla-get-propertyname x)))
                (progn
                    (vla-put-value x (vlax-make-variant val (vlax-variant-type (vla-get-value x))))
                    (cond (val) (t))
                )
            )
        )
        (vlax-invoke blk 'getdynamicblockproperties)
    )
)

;; Get Dynamic Block Property Allowed Values  -  Lee Mac
;; Returns the allowed values for a specific Dynamic Block property.
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)
;; Returns: [lst] List of allowed values for property, else nil if no restrictions

(defun LM:getdynpropallowedvalues ( blk prp )
    (setq prp (strcase prp))
    (vl-some '(lambda ( x ) (if (= prp (strcase (vla-get-propertyname x))) (vlax-get x 'allowedvalues)))
        (vlax-invoke blk 'getdynamicblockproperties)
    )
)

;; Get Visibility Parameter Name  -  Lee Mac
;; Returns the name of the Visibility Parameter of a Dynamic Block (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; Returns: [str] Name of Visibility Parameter, else nil

(defun lm:getvisibilityparametername ( blk / vis )  
    (if
        (and
            (vlax-property-available-p blk 'effectivename)
            (setq blk
                (vla-item
                    (vla-get-blocks (vla-get-document blk))
                    (vla-get-effectivename blk)
                )
            )
            (= :vlax-true (vla-get-isdynamicblock blk))
            (= :vlax-true (vla-get-hasextensiondictionary blk))
            (setq vis
                (vl-some
                   '(lambda ( pair )
                        (if
                            (and
                                (= 360 (car pair))
                                (= "BLOCKVISIBILITYPARAMETER" (cdr (assoc 0 (entget (cdr pair)))))
                            )
                            (cdr pair)
                        )
                    )
                    (dictsearch
                        (vlax-vla-object->ename (vla-getextensiondictionary blk))
                        "ACAD_ENHANCEDBLOCK"
                    )
                )
            )
        )
        (cdr (assoc 301 (entget vis)))
    )
)

(vl-load-com)

(princ
    (strcat
        "\n:: UpdateDynamicBlock.lsp"
        "\n:: Type \"UDB\" to Invoke"
    )
)

(defun c:UDB ( / sel getCells readexcel sel idx obj vis)
  
  (defun getCells (fileName sheetName cellName / xl workbook sheet range cellValue)
    (setq xl(vlax-get-or-create-object "Excel.Application"))
    (vla-put-visible xl :vlax-false)
    (vlax-put-property xl 'DisplayAlerts :vlax-false)
    (setq workbook (vl-catch-all-apply 'vla-open (list (vlax-get-property xl "WorkBooks") fileName)))
    (setq sheet (vl-catch-all-apply 'vlax-get-property (list (vlax-get-property workbook "Sheets") "Item" sheetName)))
    (vlax-invoke-method sheet "Activate")
    (setq range (vlax-get-property (vlax-get-property sheet 'Cells) "Range" cellName))
    (setq cellValue(vlax-variant-value (vlax-get-property range 'Value2)))
	  ;(setq cellValue(vlax-variant-value (vlax-get-property range 'Text)))
    (vl-catch-all-apply 'vlax-invoke-method (list workbook "Close"))
    (vl-catch-all-apply 'vlax-invoke-method (list xl "Quit"))
    (if (not (vlax-object-released-p range))(progn(vlax-release-object range)(setq range nil)))
    (if (not (vlax-object-released-p sheet))(progn(vlax-release-object sheet)(setq sheet nil)))
    (if (not (vlax-object-released-p workbook))(progn(vlax-release-object workbook)(setq workbook nil)))
    (if (not (vlax-object-released-p xl))(progn(vlax-release-object xl)(setq xl nil)))
    (if(= 'safearray (type cellValue))
      (progn
	(setq tempCellValue(vlax-safearray->list cellValue))
	(setq cellValue(list))
	(if(= (length tempCellValue) 1)
	  (progn
	    (foreach a tempCellValue
	      (if(= (type a) 'LIST)
		(progn
		  (foreach b a
		    (if(= (type b) 'LIST)
		      (setq cellValue(append cellValue (list (vlax-variant-value (car b)))))
		      (setq cellValue(append cellValue (list (vlax-variant-value b)))))))
		(setq cellValue(append cellValue (list (vlax-variant-value a)))))))
	  (progn
	    (foreach a tempCellValue
	      (setq tmpList(list))
	      (foreach b a
		(setq tmp(vlax-variant-value b))
		(setq tmpList(append tmpList (list tmp))))
	      (setq cellValue(append cellValue tmpList)))))))
    cellValue
    )
  
  (defun readexcel ( / fname sjname )
    (setq fname "C:\\foldername\\workbook.xls"
          shname "sheet1"
	  range1  "A1:A14"
	  range2  "B1:B14"
	  )

    (if (and (setq lst1 (getcells fname shname range1))
	     (setq lst2 (getcells fname shname range2)))
      
      (mapcar 'cons lst1 lst2)))
	  ;(mapcar 'cons lst1 (mapcar 'vl-princ-to-string lst2))
  
  ; ------------------------------------------------------------------------
  
  (if (and (setq sel (ssget "_X" (append '((000 . "INSERT")
					   (-04 . "<OR")
					   (002 . "`*U*"))
					 (mapcar '(lambda ( x ) (cons 2 (car x))) lst)
					 '((-004 . "OR>")
					   (410 . "Model")))))
	   (setq lst (readexcel))
	   )
    (repeat (setq idx (sslength sel))
      (if (setq idx (1- idx)
		obj (vlax-ename->vla-object (ssname sel idx))
		vis (cdr (assoc (strcase (LM:blockname obj)) lst))
		)
	(LM:SetVisibilityState obj vis))))
  (princ)
  )
0 Likes