Jump to content

Filtering a list with AutoLisp


eengebruiker

Recommended Posts

Hello,

 

I would apprecite some reactions on the following tools that I made.

 

Reading about Clojure I came across functionality that is not standard available in AutoLisp. After some thinking I programmed it myself.

 

First 2 functions which do what they are supposed to do:

(defun even? (n)
 (and (= (type n) 'INT) (= (rem n 2) 0)))

(defun odd? (n)
 (and (= (type n) 'INT) (/= (rem n 2) 0)))

The questionmark in the functionname seems appropriate.

 

So what to do when you want to filter a list of integers against one of these functions? I constructed the following:

(defun filter (f l / a)
 (foreach i l (if (apply f (list i)) (setq a (append a (list i))))) a)

 

To get you started use the following two commands:

(defun c:etest ()
 (filter 'even? (list -5 -4 -3 -2 -1 0 1 2 3 4 5)))

(defun c:otest ()
 (filter 'odd? (list -5 -4 -3 -2 -1 0 1 2 3 4 5)))

 

Although short already I wonder if the filter routine could be made more elegant/more logical.

 

One can extend the library with all kinds of name? functions, provided that return T or nil on every call. The questionmark and the name 'filter' are used for logic readability.

 

Try to make a functon that returns T if a value is of type 'STR, otherwise nil.

Next use it with the filter function.

 

It's fun and would like to see the variations that you come up with.

 

Regards,

 

André

Link to comment
Share on other sites

Hi Andre,

First of all nice job!

I'd still suggest you to take a look at this tutorial, since this task would be usually approached with the mapcar function.

 

It's fun and would like to see the variations that you come up with.

 

I have no idea where is required even/odd number filtering, but you could filter the whole list itself so it will return two separate lists, one with even and other with odd numbers.

 

(defun EvenOrOdd ( nL )
 (
   (lambda (intp f nL / tmp even odd r ) 
     (and 
       (or (vl-every 'intp nL) (prompt "\nNot an integers list") )
       (setq tmp (f nL)) 
       (setq even (vl-remove '"" (mapcar 'car tmp)))
       (setq odd (vl-remove '"" (mapcar 'cdr tmp)))
       (setq r (list even odd))
     ); and
     r
   ); lambda
   (lambda (x) (eq 'INT (type x)))
   (lambda ( nL / x )
     (if nL
       (cons 
         (if (= (rem (setq x (car nL)) 2) 0)
           (cons x "")
           (cons "" x)
         )
         (f (cdr nL))
       )
     )
   )
   nL
 )
); defun EvenOrOdd

 

Using the above:

 

(EvenOrOdd '(-5 5 6 -4 -3 -2 -1 0 1 1 7 2 3 4 5)) >> ((6 -4 -2 0 2 4) (-5 5 -3 -1 1 1 7 3 5))

 

Which means you could bound symbols for the two lists:

 

_$ (mapcar 'set '(evenL oddL) (EvenOrOdd '(-5 5 6 -4 -3 -2 -1 0 1 1 7 2 3 4 5))) >> ((6 -4 -2 0 2 4) (-5 5 -3 -1 1 1 7 3 5))
_$ evenL >> (6 -4 -2 0 2 4)
_$ oddL >> (-5 5 -3 -1 1 1 7 3 5)

 

Another example:

_$ (EvenOrOdd ((lambda ( / i L ) (repeat (setq i 15) (setq L (cons (- i) (cons (setq i (1- i)) L)))))))
>> ((0 -2 2 -4 4 -6 6 -8 8 -10 10 -12 12 -14 14) (-1 1 -3 3 -5 5 -7 7 -9 9 -11 11 -13 13 -15))

 

Another version (recursiveless :lol: ) :

(defun EvenOrOdd ( nL )
 (if (vl-every '(lambda (x) (eq 'INT (type x))) nL)
   ( (lambda (L) (mapcar '(lambda (x) (apply 'append (mapcar x L))) '(car cadr)))
     (mapcar '(lambda (x) ((if (= (rem x 2) 0) '((v)v) reverse) (list (list x) nil))) nL)
   )
 )
); defun EvenOrOdd

Edited by Grrr
Link to comment
Share on other sites

I would use vl-remove-if or vl-remove-if-not in the filter function.

Same here.

 

Another for fun:

(defun even? (n)
 (if (= (type n) 'int)
   (cond ((= (rem n 2) 0) n))
 )
)
(vl-remove 'nil (mapcar 'even? '(-5 -4 -3 -2 -1 0 1 2 3 4 5)))

Link to comment
Share on other sites

Thanks for the constructive replies. This gets very interesting.

 

@Grrr: I know about mapcar and use it a lot. The function has the habit of returning a value in the returning list against every item in the list(s) that it gets fed. You can't avoid that. I thought that it was of no use here and solved it otherwise. But is is useful combined with . . .

 

@ronjonp and @Roy_041: I overlooked vl-remove. These vl-additions are an addition that i never have fully adopted. There is no good reason for that (on the contrary). I use them once in a while, so this is kind of stupid. In combination with mapcar it makes the filter function more elegant. I was looking for that.

 

As I wrote, i came across this functionality when I studied clojure and wondered why not in AutoLisp. I wanted to have it simple and effective. Therefore for this purpose I do not want to adopt other solutions for parts of the code that you all provided. Thanks anyway . . . but if you think there's more that I am overlooking, let me know.

 

Now the interesting part.

I am left with a problem when using the changed filter function with Mapcar. I end up with a list of True's (T T T T T). Just the amount of even or odd numbers found. So I do not get a filtered list. Now I have to change the even? and odd? functions to return not a T but the number itself. I don't like that much because if I ask if 4 is even, the answer is true, not 4.

 

 

Anyway, all changes together for now:

(defun even? (n)
 (if (and (= (type n) 'INT) (= (rem n 2) 0)) n))

(defun odd? (n)
 (if (and (= (type n) 'INT) (/= (rem n 2) 0)) n))

(defun filter (f l)
 (vl-remove 'nil (mapcar f l)))

(defun c:etest ()
 (filter 'even? (list -5 -4 -3 -2 -1 0 1 2 3 4 5)))

(defun c:otest ()
 (filter 'odd? (list -5 -4 -3 -2 -1 0 1 2 3 4 5)))

 

 

Then I started to take a good look at other vl-routines and found vl-remove-if-not.

See below. This combined with even? and odd? in the way I think they should function,

makes it perfect.

 

Two notes:

- It is not only about odd? and even? as metioned earlier.

- Now using the filter-function (wrapper) becomes a matter of taste.

I like (filter . . . but (vl-remove-if-not . . . can be used directly

 

(defun even? (n)
 (and (= (type n) 'INT) (= (rem n 2) 0)))

(defun odd? (n)
 (and (= (type n) 'INT) (/= (rem n 2) 0)))

(defun filter (f l)
 (vl-remove-if-not f l))

(defun c:etest ()
 (filter 'even? (list -5 -4 -3 -2 -1 0 1 2 3 4 5)))

(defun c:otest ()
 (filter 'odd? (list -5 -4 -3 -2 -1 0 1 2 3 4 5)))

 

 

André

Link to comment
Share on other sites

@Roy_043 and @ronjonp.

I have written a reply that is not visible yet because the moderator wants to have a look first.

For some reason I read some of your replies again and saw that you had mentioned vl-remove-if-not already. I only saw vl-remove and overlooked the rest when first reading it.

So you were first with the right clues. Sorry!

 

I hope this topic is of interest for other readers and AutoLisp programmers.

 

Thanks,

 

André

Link to comment
Share on other sites

  • 2 years later...

After more than two years a final reply to this. I am happy heaving brought up the subject. I learned from it and I suppose there something in it for a lot of programmers.
What's the use of such? Well I came up with this because of what I learned from Clojure. A new Lisp that is growing steadily. In that language I found things that are not present or more inconvenient in AutoLisp.

 

As we found above, some things (and maybe everything) can be created in AutoLisp in almost the same way.
There's not much use in weeding out (un)even numbers, but i think it is valua le to have a handy way filter a list with a function of choice.

 

Thanks to all contributors,

 

André

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...