Make a new list with a specific property from a list

Make a new list with a specific property from a list

jotaferrer
Advocate Advocate
541 Views
7 Replies
Message 1 of 8

Make a new list with a specific property from a list

jotaferrer
Advocate
Advocate

Hey guys! It's been a while since last time...

 

I am creating a lisp but I'm not sure how I'll achieve what I need.

 

I need to take each Perimeter from my vla-object list items, and then make a new list with perimeter values only.

 

Can someone please help me? Thanks in advance! 

0 Likes
Accepted solutions (1)
542 Views
7 Replies
Replies (7)
Message 2 of 8

pbejse
Mentor
Mentor

@jotaferrer wrote:

I need to take each Perimeter from my vla-object list items, and then make a new list with perimeter values only.


Are these known "Perimeter" ? IF yes you can directly create the list with values only, as an example

(defun c:demo ( / vlaobj ValuesOnly)  
    (and
    	(setq vlaobj (car (entsel "\nSelect object")))
	(setq vlaobj (vlax-ename->vla-object vlaobj))
	(print (setq ValuesOnly
	       	(mapcar '(lambda (d)
			  (Vlax-get vlaobj d))
		   '("ObjectName" "Layer" "Linetype"));<-- known properties
	      )
	)
      )(princ)
  )

 

 

Message 3 of 8

john.uhden
Mentor
Mentor

I am just imagining the scenario, but say you had a list of objects each having a list of properties in the same order, such as...

'(handle layer area perimeter).

Much as in the same way you would extract data from Excel, you would transpose the data into rows, with the first row being the headers.  Let's give it the symbol name 'data...

(setq data '(

  ("handle" "layer" "area" "perimeter")

  ("1A13" "grass" 4010.24 602.45)

  ("1B15" "sand" 8723.22 1247.66)

  ;; etc.

))

(setq headers (car data))

To get all, but only, the perimeters...

(setq perimeters (mapcar '(lambda (x)(nth (vl-position "perimeter" headers) x))(cdr data)))

 

To get the sum of grass areas, you would use vl-remove-if-not to grab only the items with the "grass" layers and perform the same kind of mapcar contained within an (apply '+ <grass_items>)

John F. Uhden

Message 4 of 8

calderg1000
Mentor
Mentor

Regards @jotaferrer 

Maybe this will help, I understand that it is about selecting line or polyline objects

 

(defun c:nlt (/ s nlist i lper)
  (setq s (ssget '((0 . "*line"))))
  (setq nlist ())
  (repeat (setq i (sslength s))
    (setq enam (vlax-ename->vla-object (ssname s (setq i (1- i)))))
    (setq lper (vla-get-length enam))
    (setq nlist (cons lper nlist))
  )
  (princ (reverse nlist))
  (princ)
)

 

 


Carlos Calderon G
EESignature
>Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

Message 5 of 8

jotaferrer
Advocate
Advocate

Hey @pbejse @john.uhden @calderg1000 sorry guys! I totally forgot to post my lisp... My bad...

 

That's what I have so far. I want to create a loop that takes only the perimeter from my lst so that I make a new list with all perimeters only. No matter if I have 2 or 200 objects. 

 

 

 (setq ss (ssget "_A"))

 (command ".region" ss "")

 (setq $ss (ssget "_A"))

 (if $ss
        (repeat (setq i (sslength $ss))
            (setq lst (cons (vlax-ename->vla-object (ssname $ss (setq i (1- i)))) lst))
        )
    ) ; ssget = list and vla-object too

 (setq i (sslength $ss))
 (if (> (vl-list-length lst) 1)
  (progn
   (foreach i lst
    (setq objper (vlax-get i 'perimeter))

 

 

0 Likes
Message 6 of 8

pbejse
Mentor
Mentor
Accepted solution

@jotaferrer wrote:

Hey @pbejse @john.uhden @calderg1000 sorry guys! I totally forgot to post my lisp... My bad...

 

That's what I have so far. I want to create a loop that takes only the perimeter from my lst so that I make a new list with all perimeters only. No matter if I have 2 or 200 objects. 


No worries buddy..You are almost there.

You can directly assign the values in one loop.

(repeat (setq i (sslength $ss))
            (setq lst (cons
			(vlax-get 
				(vlax-ename->vla-object (ssname $ss (setq i (1- i)))) 'perimeter)
				lst))
        )

Or make a list of two items in the first loop.

 

(repeat (setq i (sslength $ss))
	    (setq lst (cons
			(list (Setq e (vlax-ename->vla-object (ssname $ss (setq i (1- i)))))
			      (vlax-get e 'Perimeter))
			      lst))
	  	
	)

 

Wherein the second item of the list is the value of the perimeter property. This way, the user can modify the property after the list is created if needed. If you need only the values you can use 

 

(setq values (mapcar 'cadr lst))

 

Now if you have a list of multiple properties

(defun c:demo ( / properties i ss setq perimeter_list)
(setq properties '("Perimeter" "ProductOfInertia" "RadiiOfGyration"))
(if
  (ssget "_A" (list '(0 . "LWPOLYLINE") (cons 410  (getvar 'ctab))));<-- only select Lwpolylines on current space
	(progn    
		(command ".region" "p" "")
		(setq ss (ssget "_A" (list '(0 . "REGION") (cons 410  (getvar 'ctab)))))
		(repeat (setq i (sslength ss))
		  (Setq vlaobj (vlax-ename->vla-object (ssname ss (setq i (1- i)))))
		    (setq lst (cons
				(mapcar '(lambda (d)
						 (list d  (Vlax-get vlaobj d))) properties)
				      lst))	  	
			) ; ssget = list and vla-object too
	  
  ;;	sample for perimeter
		(foreach itm lst
		  (if (setq f (assoc "Perimeter" itm))
		    	(setq perimeter_list (cons (cadr f) perimeter_list))))
		(print perimeter_list)
  		)
  	)
  (princ)
  )

Important that you declare the variables as local to prevent the list created by cons from expanding uncontrollably

 

HTH

 

Message 7 of 8

jotaferrer
Advocate
Advocate

NO WAAAAY @pbejse hahaha it was in front of me all that time! All that I needed to do was "only" put a 'perimeter at the end of that line. 😅

 

Thank you so much! That's was exactly what I was looking for. Now I'll keep it up to finish my lisp. I think I'm able to finish it by my self, but if don't, I'll come back here for your kindly help guys! Thanks for help me again buddy!

0 Likes
Message 8 of 8

pbejse
Mentor
Mentor

@jotaferrer wrote:

NO WAAAAY @pbejse hahaha it was in front of me all that time! All that I needed to do was "only" put a 'perimeter at the end of that line. 😅

There you go! Keep on coding @jotaferrer 👍