Author Topic: Setting a variable based on contents on list.  (Read 2436 times)

0 Members and 1 Guest are viewing this topic.

EWCAD

  • Mosquito
  • Posts: 14
Setting a variable based on contents on list.
« on: May 22, 2023, 03:24:19 PM »
I am trying to set a variable to one of the values returned by an intersection function, The issue I'm having is that I need to always set the variable with the item that has the highest Y value. Now to be honest I can think of a few ways I could do this but I'm certain there has to be a better way than say, setting a variable for each member of the list and comparing them then setting the final variable to the one with the highest value... I'm hoping maybe I can filter through the resulting list before any variables are set, maybe with a foreach? I'm still learning the ins and outs of list manipulation so any help is appreciated!

for reference I'm feeding 2 selection sets to a function that creates a list of all intersecting points between the 2. first ss is just a 90 degree line and second one is a closed arc polygon. So at most I only end up with 2-3 intersections with the shapes I'm working with, if more context is needed I will happily oblige!


JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Setting a variable based on contents on list.
« Reply #1 on: May 22, 2023, 03:41:07 PM »
Trying to understand; you have a list of numbers and you want to find the entry that is the largest?

Example (I understand you may be talking about a point list, but the principle is the same):
If you have a list of numbers: (1 2 3 4 5 6 7)
you want to find the number 7. correct?

What does your list look like?
(1 2 (3 4) 5 6 (7)) ; nested lists
(1 2 nil 3 4 5 nil 6 7) ; null entries
etc.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

EWCAD

  • Mosquito
  • Posts: 14
Re: Setting a variable based on contents on list.
« Reply #2 on: May 22, 2023, 03:55:56 PM »
Exactly, I really just need to check the Y value of each item and compare them to find the one with the greatest value. Here is a sample of what the returned lists look like, This is 4 intersection points.

((288.252 -56.8312 0.0) (288.252 -57.3313 0.0) (288.252 -57.9562 0.0) (288.252 -58.4563 0.0))

So in this example the point I would want is the last one in the list.

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #3 on: May 22, 2023, 04:29:50 PM »
Perhaps,
from my library :

Code - Auto/Visual Lisp: [Select]
  1. (defun kdub:miny (pointlist)
  2.   (apply (function min) (mapcar (function cadr) pointlist))
  3. )
  4.  


(kdub:miny '((288.252 -56.8312 0.0) (288.252 -57.3313 0.0) (288.252 -57.9562 0.0) (288.252 -58.4563 0.0)))

;;-> -58.4563
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #4 on: May 22, 2023, 04:32:32 PM »

oh, wait, Did you want the axis or the point ??
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Setting a variable based on contents on list.
« Reply #5 on: May 22, 2023, 04:48:01 PM »
Kerry already has a good framework but here is another approach.

I would try something like:
Code - Auto/Visual Lisp: [Select]
  1. (defun return-if (proced lst sofar)
  2.   (if (null lst)                                                ; -If the list is empty, return what we have.
  3.     sofar
  4.     (return-if                                                  ; -Keep looking through the list...
  5.       proced
  6.       (cdr lst)                                                 ;  Of the next item in the list
  7.       (if (eval (list proced (cadr (car lst)) (cadr sofar)))    ;  if the current item in the list is bigger/smaller/etc.
  8.         (car lst)                                               ;  then set it to the `sofar` procedure.
  9.         sofar))) )                                              ;  else just keep using the `sofar` variable.

Code: [Select]
(setq aList '((288.252 -56.8312 0.0) (288.252 -57.3313 0.0) (288.252 -57.9562 0.0) (288.252 -58.4563 0.0)))
(return-if '< aList (car aList)) ; set `sofar` to the first item in the list
> (288.252000 -58.456300 0.000000)

Study functions and ask questions.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #6 on: May 22, 2023, 06:05:20 PM »

This may suit ?

Code - Auto/Visual Lisp: [Select]
  1.  
  2. (setq pointlist '( (1 -56.8312 8) (2 -57.3313 7) (3 -57.9562 6) (4 -58.4563 5)))
  3.  
  4. (setq smallest_y
  5.        (car
  6.          (vl-sort pointlist
  7.                   '(lambda (a b) (< (cadr a) (cadr b)))
  8.          )
  9.        )
  10. )
  11.  
  12.  

==> (4 -58.4563 5)
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

EWCAD

  • Mosquito
  • Posts: 14
Re: Setting a variable based on contents on list.
« Reply #7 on: May 22, 2023, 06:24:28 PM »
My mistake, I said what I meant but was in a hurry with my reply and pointed out the wrong example. I did in fact mean the Y value that is the largest, but I pointed out the smallest one. However yes, I believe all of the examples above are something I could work in to sort through the data. I am assuming that I can flip the less than to a greater than in the vl-sort and get the desired results. If nothing else, I'll find out lol

Thank you both for your help, I appreciate it!

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #8 on: May 22, 2023, 06:32:09 PM »
>>>  I am assuming that I can flip the less than to a greater than in the vl-sort and get the desired results. If nothing else, I'll find out lol

Yes, that will work.

Stay well
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Setting a variable based on contents on list.
« Reply #9 on: May 23, 2023, 02:09:49 AM »
Hi,

Another approch using some functions mimic the F# List.fold, List.reduce, List.minBy, ListmaxBy funtions.
Code - Auto/Visual Lisp: [Select]
  1. ;; gc:fold
  2. ;; Applies a function to each element of the list,
  3. ;; threading an accumulator argument through the computation.
  4. ;;
  5. ;; Arguments
  6. ;; folder: function that updates the state with each element from the sequence.
  7. ;;         If the input function is f and the elements are i0...iN then computes
  8. ;;         (f ... (f s i0) ... iN)
  9. ;; state: initial state.
  10. ;; source: input list.
  11. (defun gc:fold (folder state source / f)
  12.   (setq f (eval folder))
  13.   (foreach n source (setq state (f state n)))
  14. )
  15.  
  16. ;; gc:reduce
  17. ;; Applies a function to each element of the list,
  18. ;; threading an accumulator argument through the computation.
  19. ;; Begin by applying the function to the first two elements.
  20. ;; Then feed this result into the function along with the third element and so on.
  21. ;; Return the final result.
  22. ;;
  23. ;; Arguments
  24. ;; reduction: function that takes in the current accumulated result and the next
  25. ;;            element of the sequence to produce the next accumulated result.
  26. ;; source: input list.
  27. (defun gc:reduce (reduction source)
  28.   (gc:fold reduction (car source) (cdr source))
  29. )
  30.  
  31. ;; gc:minBy
  32. ;; Returns the lowest of all elements of the list,
  33. ;; compared via < operator on the function result.
  34. ;;
  35. ;; Arguments
  36. ;; projection: function to transform items from the input sequence into comparable keys.
  37. ;; source: input list.
  38. (defun gc:minBy (projection source)
  39.   (setq p (eval projection))
  40.   (gc:reduce (function (lambda (a b) (if (< (p b) (p a)) b a))) source)
  41. )
  42.  
  43. ;; gc:maxBy
  44. ;; Returns the greatest of all elements of the list,
  45. ;; compared via > operator on the function result.
  46. ;;
  47. ;; Arguments
  48. ;; projection: function to transform items from the input sequence into comparable keys.
  49. ;; source: input list.
  50. (defun gc:maxBy (projection source)
  51.   (setq p (eval projection))
  52.   (gc:reduce (function (lambda (a b) (if (> (p b) (p a)) b a))) source)
  53. )

Code - Auto/Visual Lisp: [Select]
  1. _$ (gc:minBy 'cadr '((1 -56.8312 8) (2 -57.3313 7) (3 -57.9562 6) (4 -58.4563 5)))
  2. (4 -58.4563 5)
  3. _$ (gc:maxBy 'cadr '((1 -56.8312 8) (2 -57.3313 7) (3 -57.9562 6) (4 -58.4563 5)))
  4. (1 -56.8312 8)

@Kerry, the (function min) and (function cadr) are useless because 'min' and 'cadr' are already compiled function. IOW, the 'function' function is only usefull with 'lambda' expressions.
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Setting a variable based on contents on list.
« Reply #10 on: May 23, 2023, 02:13:54 AM »
Without using the upper functions, minBy and maxBy could have been written like this:
Code - Auto/Visual Lisp: [Select]
  1. (defun minBy (projection source / f a)
  2.   (setq f (eval projection)
  3.         a (car source)
  4.   )
  5.   (foreach x (cdr source)
  6.     (if (< (f x) (f a))
  7.       (setq a x)
  8.     )
  9.   )
  10.   a
  11. )
  12.  
  13. (defun maxBy (projection source / f a)
  14.   (setq f (eval projection)
  15.         a (car source)
  16.   )
  17.   (foreach x (cdr source)
  18.     (if (> (f x) (f a))
  19.       (setq a x)
  20.     )
  21.   )
  22.   a
  23. )
Speaking English as a French Frog

BIGAL

  • Swamp Rat
  • Posts: 1409
  • 40 + years of using Autocad
Re: Setting a variable based on contents on list.
« Reply #11 on: May 23, 2023, 02:20:00 AM »
Why not just sort the list based on the Y value it can be either min or max depending on use of < or >

Code: [Select]
;x only
(setq lst (vl-sort lst '(lambda (j k) (< (car j)(car k)))))
; Y
;x only
(setq lst (vl-sort lst '(lambda (j k) (< (cadr j)(cadr k)))))
A man who never made a mistake never made anything

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Setting a variable based on contents on list.
« Reply #12 on: May 23, 2023, 03:01:45 AM »
Why not just sort the list based on the Y value it can be either min or max depending on use of < or >

Code: [Select]
;x only
(setq lst (vl-sort lst '(lambda (j k) (< (car j)(car k)))))
; Y
;x only
(setq lst (vl-sort lst '(lambda (j k) (< (cadr j)(cadr k)))))

This is Kerry's proposal on reply #6.

I wanted to show another way with some generic higher order funtions.
Theorically aggregating (folding) a list is cheaper than sorting it because it iterates the list only once.
Speaking English as a French Frog

bruno_vdh

  • Newt
  • Posts: 107
Re: Setting a variable based on contents on list.
« Reply #13 on: May 23, 2023, 06:00:25 AM »
Hi,
My code proposal
(setq lst '((288.252 -56.8312 0.0) (288.252 -57.3313 0.0) (288.252 -57.9562 0.0) (288.252 -58.4563 0.0)))


The dot with the largest Y
Code - Auto/Visual Lisp: [Select]
  1. _$ (foreach p lst (if (< (cadr pmaxY)  (cadr p)) (setq pmaxY p) pmaxY))
  2. (288.252 -56.8312 0.0)

The dot with the smallest Y
Code - Auto/Visual Lisp: [Select]
  1. _$ (foreach p lst (if (< (cadr pminY) (- (cadr p))) (setq pminY p) pminY))
  2. (288.252 -58.4563 0.0)

To make a more generic filtering function
Code - Auto/Visual Lisp: [Select]
  1. (defun filter_rank_size (rank size l / p)
  2.   (setq rank (eval rank)
  3.         size (eval size)
  4.   )
  5.   (foreach x l
  6.     (if (< (rank p) (size (rank x)))
  7.       (setq p x)
  8.       p
  9.     )
  10.   )
  11. )

Search for the largest and smallest Y
Code - Auto/Visual Lisp: [Select]
  1. _$ (filter_rank_size 'cadr '+ lst)
  2. (288.252 -56.8312 0.0)
  3. _$ (filter_rank_size 'cadr '- lst)
  4. (288.252 -58.4563 0.0)


EWCAD

  • Mosquito
  • Posts: 14
Re: Setting a variable based on contents on list.
« Reply #14 on: May 23, 2023, 07:29:40 AM »
These are all extremely helpful examples, I've just implemented one of the sorting methods above and I appreciate everyone's input! It's great to see so many different methods to get the same result. Again, thank you all for your help!