Author Topic: Setting a variable based on contents on list.  (Read 2356 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: 10605
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: 2125
  • 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: 2125
  • 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: 10605
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: 2125
  • 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: 2125
  • 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: 1398
  • 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!

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2125
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #15 on: May 23, 2023, 04:53:28 PM »
Quote from:  @ gilles

@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.

You're correct. The redundant function is wasted, even though it works.  I have some similar methods in my library that I've been using for 20+ years.

That's time I'll never get back   :cry:   :-D

The corrected method in Post Reply #3 would be :

Code - Auto/Visual Lisp: [Select]
  1. // return the smallest Y value from a list of points
  2.  
  3. (defun kdub:miny (pointlist)
  4.   (apply 'min (mapcar 'cadr pointlist))
  5. )
  6.  
  7.  


(setq pointlist '( ( 1 -56.8312 8 ) ( 2 -57.3313 7 ) ( 3 -57.9562 6 ) ( 4 -58.4563 5 )))

(kdub:miny pointlist)

;;==>  -58.4563

« Last Edit: May 23, 2023, 05:01:17 PM by kdub_nz »
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.

bruno_vdh

  • Newt
  • Posts: 107
Re: Setting a variable based on contents on list.
« Reply #16 on: May 24, 2023, 05:28:21 AM »
Hi,

I've just implemented one of the sorting methods above and I appreciate everyone's input!

Based on the following idea:
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.

And taking up the previous proposals of (gile) on reply #10, It is possible to adapt a generic search function based on the model of the function (VL-sort list comparison-function), without having to sort:
Code - Auto/Visual Lisp: [Select]
  1. (defun wanted (l f / a)
  2.   (setq f (eval f)
  3.         a   (car l)
  4.   )
  5.   (foreach x (cdr l)
  6.     (if (f a x) a (setq a x))
  7.   )
  8. )

Search for the largest and smallest Y
Code: [Select]
_$ (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)))
((288.252 -56.8312 0.0) (288.252 -57.3313 0.0) (288.252 -57.9562 0.0) (288.252 -58.4563 0.0))

_$ (wanted lst (function (lambda (a b) (> (cadr a) (cadr b)))))
(288.252 -56.8312 0.0)
_$ (wanted lst (function (lambda (a b) (< (cadr a) (cadr b)))))
(288.252 -58.4563 0.0)




kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2125
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #17 on: May 24, 2023, 05:45:18 PM »
For giggles.

Code - Auto/Visual Lisp: [Select]
  1. Benchmarking-V2 :Boundary=500 [M.P.2005 <revised kdub 2005,2014>] .................
  2. Elapsed milliseconds for 16384 iteration(s)/ relative Timing :
  3.  
  4.     (CAR (VL-SORT POINTLIST (QUOTE (LAMB...).....937 / 1.8159 <slowest>: 0.05718994ms Per iteration
  5.     (WANTED POINTLIST (FUNCTION (LAMBDA ...).....797 / 1.5446
  6.     (FOREACH P POINTLIST (IF (< (CADR PM...).....766 / 1.4845
  7.     (FILTER_RANK_SIZE (QUOTE CADR) (QUOT...).....672 / 1.3023
  8.     (GC:MINBY (QUOTE CADR) POINTLIST)............640 / 1.2403
  9.     (MINBY (QUOTE CADR) POINTLIST)...............516 / 1.0000 <fastest>: 0.03149414ms Per iteration
  10.  


Gilles takes the speed prize, again  . . . a bag of black (virtual) jellybeans  :)

Well done Sir !!
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: 10605
Re: Setting a variable based on contents on list.
« Reply #18 on: May 24, 2023, 07:03:04 PM »
Did mine make the list?

However, I reserve the right to edit your post/results if mine registers too high up the list--which, considering the company, is highly likely--(putting code up for a speed test against some of you people is like purposely banging your head against a wall).
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: 2125
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #19 on: May 24, 2023, 07:41:57 PM »
Did mine make the list?

However, I reserve the right to edit your post/results if mine registers too high up the list--which, considering the company, is highly likely--(putting code up for a speed test against some of you people is like purposely banging your head against a wall).

Sorry John, I rushed that a bit too much.
I'll add your return-if shortly.
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: 2125
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #20 on: May 24, 2023, 07:50:18 PM »
Ta da da dahhh

Code - Auto/Visual Lisp: [Select]
  1. Benchmarking-V2 :Boundary=500 [M.P.2005 <revised kdub 2005,2014>] .................
  2. Elapsed milliseconds for 16384 iteration(s)/ relative Timing :
  3.  
  4.     (RETURN-IF (QUOTE <) POINTLIST (CAR ...).....1781 / 3.2559 <slowest>: 0.10870361ms Per iteration
  5.     (CAR (VL-SORT POINTLIST (QUOTE (LAMB...)......969 / 1.7715
  6.     (WANTED POINTLIST (FUNCTION (LAMBDA ...)......828 / 1.5137
  7.     (FOREACH P POINTLIST (IF (< (CADR PM...)......781 / 1.4278
  8.     (FILTER_RANK_SIZE (QUOTE CADR) (QUOT...)......704 / 1.2870
  9.     (GC:MINBY (QUOTE CADR) POINTLIST).............687 / 1.2559
  10.     (MINBY (QUOTE CADR) POINTLIST)................547 / 1.0000 <fastest>: 0.03338623ms Per iteration
  11.  


 :wink:
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: 10605
Re: Setting a variable based on contents on list.
« Reply #21 on: May 24, 2023, 08:17:03 PM »
See wall. Bang head!

300 times worse!?
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8662
  • AKA Daniel
Re: Setting a variable based on contents on list.
« Reply #22 on: May 24, 2023, 08:18:01 PM »
a bag of black (virtual) jellybeans  :)

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2125
  • class keyThumper<T>:ILazy<T>
Re: Setting a variable based on contents on list.
« Reply #23 on: May 24, 2023, 08:44:05 PM »
See wall. Bang head!

300 times worse!?

No !
3.2559 times as long to run. Still pretty good @  0.10870361ms Per iteration

So stay chilly
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.

bruno_vdh

  • Newt
  • Posts: 107
Re: Setting a variable based on contents on list.
« Reply #24 on: May 25, 2023, 06:03:36 AM »
Hello,

See wall. Bang head!

300 times worse!?

No!
The approach was the right one because you had not sorted
After a slight rewrite:
Code - Auto/Visual Lisp: [Select]
  1. (defun return-if-V2 (proced lst / foo)
  2.   (defun foo (f l a)
  3.     (cond ((null l) a)
  4.           ((f (cadr a) (cadar l)) (foo f (cdr l) a))
  5.           (T (foo f (cdr l) (car l)))
  6.     )
  7.   )  
  8. (foo (eval proced) (cdr lst) (car lst))
  9. )
  10.  
  11. _$ (return-if-V2 '< aList )
  12. (288.252 -58.4563 0.0)
  13.  

Code: [Select]
Benchmarking ...................Elapsed milliseconds / relative speed for 65536 iteration(s):

    (RETURN-IF-V2 (QUOTE <) ALIST)..............1515 / 3.35 <fastest>
    (RETURN-IF (QUOTE <) ALIST (CAR ALIST)).....5079 / 1 <slowest>

VovKa

  • Water Moccasin
  • Posts: 1626
  • Ukraine
Re: Setting a variable based on contents on list.
« Reply #25 on: May 25, 2023, 06:54:00 AM »
i would benchmark all functions compiled
and i guess bruno's simple foreach will win