Mapcar

Mapcar

vishshreevT578L
Advocate Advocate
1,930 Views
10 Replies
Message 1 of 11

Mapcar

vishshreevT578L
Advocate
Advocate

(setq _lines (ssget '((0 . "line"))))

(defun pl:entlst-from-ss (ss)
(vl-remove-if 'listp (mapcar 'cadr (ssnamex ss)))
)

(if _lines
(setq _lines (mapcar 'pl:extr-pnt-from-line (pl:entlst-from-ss _lines)))
)

(defun pl:extr-pnt-from-line (_line / _p1 _p2)
(setq _line (entget _line))
(setq _p1 (cdr (assoc 10 _line)))
(setq _p2 (cdr (assoc 11 _line)))
(list (list (car _p1) (cadr _p1))
(list (car _p2) (cadr _p2))
) ;_ end of list
)

(defun pl:extr-pnt-from-line ()
(mapcar '(lambda).........

 

i get the list of coordinates using the above method but i want do it using mapcar

Shreev
0 Likes
1,931 Views
10 Replies
Replies (10)
Message 2 of 11

SeeMSixty7
Advisor
Advisor
Why? Mapcar is useful for running something against a list of things. a Line has 2 points that's it. You would have to build a list to tell Mapcar to extract the dxf codes for 10 and 11 and then be done.
(defun pl:extr-pnt-from-line (lineent) (setq linedata (entget lineent) linepointlist (list (cdr (assoc 10 linedata)) (cdr (assoc 11 linedata))) ) Good luck
0 Likes
Message 3 of 11

vishshreevT578L
Advocate
Advocate
You are right sir
But for this is tried to get just ent it gives me bad argument entity name
Shreev
0 Likes
Message 4 of 11

SeeMSixty7
Advisor
Advisor
(defun pl:extr-pnt-from-line (lineent)
(setq linedata (entget lineent)
linepointlist (list (cdr (assoc 10 linedata)) (cdr (assoc 11 linedata)))
)
)


You will need to call it and pass a line entity to the function.
Try this
(PL:extr-pnt-from-line (car (entsel "\nSelect Line:"))) Good luck.
0 Likes
Message 5 of 11

Ranjit_Singh
Advisor
Advisor

I tried your code and it works fine, gives no error. Post your drawing if possible.

 

Here's a different method. Pass the same selection set and see if this gives you an error too.

 

(defun somefunc (_lines)
     (if _lines
          (mapcar '(lambda (x)
                        (mapcar '(lambda (x) (reverse (cdr (reverse (cdr x)))))
                                (list (assoc 10 (entget (cadr x))) (assoc 11 (entget (cadr x))))
                                ) ;_ mapcar
                        ) ;_ lambda
                  (member (nth (- (sslength _lines) 1) (ssnamex _lines)) (reverse (ssnamex _lines)))
                  ) ;_ mapcar
          "No Lines found!"
          ) ;_ if
     ) ;_ defun
0 Likes
Message 6 of 11

Kent1Cooper
Consultant
Consultant

@vishshreevT578L wrote:

....

(defun pl:extr-pnt-from-line (_line / _p1 _p2)

(setq _line (entget _line))
....

(defun pl:extr-pnt-from-line ()
(mapcar '(lambda).........

 

i get the list of coordinates using the [upper] above method but i want do it using [lower approach] mapcar


I can't help but wonder why it matters what function you use, as long as you get the result you want, but still....

 

Using, for the initial _line argument [as in that upper function definition], the entity name of a Line, this is as close as I have been able to get using (mapcar) as an outermost function:

(mapcar
  '(lambda (x)
    (list (list (cadar x) (caddar x)) (list (cadadr x) (caddr (cadr x))))
  ); lambda
  (list (vl-remove-if-not '(lambda (y) (member (car y) '(10 11))) (entget _line)))
); mapcar

 

However, that returns this [from a random Line I picked in a drawing]:


(((567.25 86.375) (567.25 136.0)))

 

which is a list containing the list I think you want of the start- and end-points' XY coordinates.  It has extra parentheses around it.

 

I just don't think (mapcar) is the right function to do this, since it's really for mapping something such as a '(lambda) function across multiple items in a list, and it returns a new list of the results of applying that to each item in the original list.  To get (mapcar) to return one thing [your desired single list, containing two XY point lists], it needs to be applied to a list containing only one item, which is why I wrapped the stripped-down start-and-end-only entity data sublist inside another (list) function.  But that's also why it returns the list you want as an element inside another list.  If you just change the (mapcar) function name to (apply) instead, it returns it directly as the list you want, without the extra parentheses around it.  Or, if you really insist on using (mapcar) specifically, you can wrap that whole (mapcar) thing inside a (car) function, to pull the one thing out of the list that the (mapcar) part returns:

(car

  (mapcar
    '(lambda (x)
      (list (list (cadar x) (caddar x)) (list (cadadr x) (caddr (cadr x))))
    ); lambda
    (list (vl-remove-if-not '(lambda (y) (member (car y) '(10 11))) (entget _line)))
  ); mapcar

); car

 

But then (mapcar) is a nested function, if you can live with that.  I don't guarantee there's no way to get it as an outermost function to return the list you want directly, as (apply) does, but I would suggest just using (apply) instead.  If that's not acceptable, can you describe why it's essential to use (mapcar) specifically?

Kent Cooper, AIA
0 Likes
Message 7 of 11

vishshreevT578L
Advocate
Advocate

Ranjit Sir 

 

(setq _lines (ssget '((0 . "line"))))

(defun pl:entlst-from-ss (ss)
(vl-remove-if 'listp (mapcar 'cadr (ssnamex ss)))
)

(if _lines
(setq _lines (mapcar 'pl:extr-pnt-from-line (pl:entlst-from-ss _lines)))
)

(defun pl:extr-pnt-from-line (_line / _p1 _p2)
(setq _line (entget _line))
(setq _p1 (cdr (assoc 10 _line)))
(setq _p2 (cdr (assoc 11 _line)))
(list (list (car _p1) (cadr _p1))
(list (car _p2) (cadr _p2))
) ;_ end of list
)

(defun pl:extr-pnt-from-line ( dxf )
(mapcar '(lambda (x) (list (cdr (assoc 10 x)) (cdr (assoc 11 x)))) dxf)
)

 

i wanted to try this function using mapcar instead of highlighted code

Shreev
0 Likes
Message 8 of 11

vishshreevT578L
Advocate
Advocate
Sir i am totally confused with this function.....mapcar is like getting
married again.... how i am going to understand this function its a question
yesterday i manipulated polyline using mapcar so i thought same i will do
for line...thats it
Shreev
0 Likes
Message 9 of 11

SeeMSixty7
Advisor
Advisor
Shreev,

There are enough MAPCARS in this thread to confuse anyone. LOL.

I typically stay away from mapcar except for basic list manipulation, as beyond that it can get confusing and later make your code hard to read.
I stick with good ole' While Loops. That way I can call a variety of functions and do just about anything inside that code segment I need to do.

It sounds like you are trying to learn more and more. I'm glad to help when ever I can and I do believe the guys responding here are doing the same.

Good luck and keep Lisping.
0 Likes
Message 10 of 11

vishshreevT578L
Advocate
Advocate
Sir i know nothing about it.
But yea i want to be expert today everything i do in this language says me
u better quit....i even quit and sleep but morning torchers me and i come
here again...
Please keep guiding me sir
Shreev
Message 11 of 11

Ranjit_Singh
Advisor
Advisor

Your code will generate error. Give some more thought to what mapcar does and you will see the problem. I will try to explain

Command: (mapcar '(lambda (x) (list (cdr (assoc 10 x)) (cdr (assoc 11 x)))) entdata)
; error: bad association list: (-1 . <Entity name: 7ffff3ec490>)

 

 

Your above line of code will take the car of the dxf list (that you pass as dxf in your code) and look for (assoc 10 x). We don't have (assoc 10 x), because mapcar is looking at car of your dxf which is (-1 . <Entity name: 7ffff3ec490>). Think, what would be the assoc 10 of (-1 . <Entity name: 7ffff3ec490>)?. That's why you get the error.

 

Let's take one step at a time. Mapcar as the name suggests maps a function to the car of a list (it goes in sequential order; car of a list, then the car of the cdr of the list, and then next and so on). To catch 10 and 11 dxf codes, lets pass the entdata to a mapcar. Remember, we only need to catch 10 and 11 codes, so you need a conditional statement in there. Many ways to do it but I am going to use cond. You can use if or whatever you prefer. Lets say entdata is my pointer to entget list of a line

 

command: (mapcar '(lambda (x) (cond ((= (car x) 10) (cdr x)) ((= (car x) 11) (cdr x)) (T ()))) entdata)
(nil nil nil nil nil nil nil nil nil nil (15.7903 -3.81105 0.0) (29.2622 12.1024 0.0) nil)

mapcar will always return the same length list as the list passed to the function (this makes sense since it looks at every member of the list and applies the lambda function); in above case, length of entdata. Remove nil however you want (vl-remove-nil) is the easiest

 

Command: (vl-remove nil (mapcar '(lambda (x) (cond ((= (car x) 10) (cdr x)) ((= (car x) 11) (cdr x)) (T ()))) entdata))
((15.7903 -3.81105 0.0) (29.2622 12.1024 0.0))

It seems like an overkill but mapcar is very efficient. Think of it in terms of an in-built while or foreach or whatever you want to call. Now, since you have a whole selection set of lines, write another mapcar on top of this mapcar to pass each line. Give it a try and see if it works.