How to fix contract violation errors in scheme DrRacket? - list

(define is1?
(lambda (tuple)
(if (and (= 2 (length tuple))
(= 1 (- (cadr tuple) (car tuple)))
(list? tuple))
#t
#f)))
(define greenlist?
(lambda (x) (andmap is1? x)))
(greenlist? '((2 4 6) (5 6) (1 2)))
(greenlist? '(3 4 5 6))
The second command: (greenlist? '(3 4 5 6)) returns an error when it should return false.
Instead I get this error:
length: contract violation
expected: list?
given: 3
What should I change in my code so it returns false instead of an error?
Here is the definition of a greenlist:
A greenlist is a non-empty list of pairs of integers where a pair of
integers is a list of exactly two integers and where each pair '( x y) has the property that y – x = 1.
Example: '((5 6) (3 4) (2 3) (-5 -4)) is a greenlist.

The problem is that the order of the conditions matters: in an and expression the conditions are evaluated in left-to-right order, if one condition is false then the other conditions are skipped (short-circuit evaluation).
Your input is a list of lists, so you should test first if the current element is an actual list - otherwise you'll attempt to take the length of an object which isn't a list (the number 3 in your example), which is an error.
By the way: it's possible to simplify the code, you don't actually need to use an if, just return the value of the condition:
(define is1?
(lambda (tuple)
(and (list? tuple) ; you must ask this first!
(= 2 (length tuple))
(= 1 (- (cadr tuple) (car tuple))))))

Related

Lisp reversing all continuous sequences of elements

I want to reverse only the continuous sequences, not all the elements of my original list.
Ex:
(reverseC '( 1 2 ( 4 5 ) 5 ) ) => ( 2 1 ( 5 4 ) 5 )
(reverseC '(1 4 2 (3 4) 9 6 (7 8)))) => (2 4 1 (4 3) 6 9 (8 7))
I was thinking of splitting it into 2 functions: one to reverse a simple list ( 1 2 3 ) -> ( 3 2 1 ) and one function
(main) to determine the continuous sequences, make a list out of them, apply reverse on that list and the remake the whole reversed list.
(defun reverse-list ( lista )
(if (eql lista () )
()
(append (reverse-list (cdr lista )) (list ( car lista)))
)
)
This is the reverse function but I have no idea how to do the other one. I'm new to Lisp and I come from Prolog so it's a pretty big change of scenery. Any idea is welcome.
(defun reverse-more (L)
(if (eql L nil)
nil
(let ( el (car L)) (aux (cdr L)))
(if (eql (listp el) nil)
...No idea on the rest of the code ...
There's already an accepted answer, but this seems like a fun challenge. I've tried to abstract some of the details away a bit, and produced a map-contig function that calls a function with each contiguous sublist of the input list, and determines what's a contiguous list via a predicate that's passed in.
(defun map-contig (function predicate list)
"Returns a new list obtained by calling FUNCTION on each sublist of
LIST consisting of monotonically non-decreasing elements, as determined
by PREDICATE. FUNCTION should return a list."
;; Initialize an empty RESULT, loop until LIST is empty (we'll be
;; popping elements off of it), and finally return the reversed RESULT
;; (since we'll build it in reverse order).
(do ((result '())) ((endp list) (nreverse result))
(if (listp (first list))
;; If the first element is a list, then call MAP-CONTIG on it
;; and push the result into RESULTS.
(push (map-contig function predicate (pop list)) result)
;; Otherwise, build up sublist (in reverse order) of contiguous
;; elements. The sublist is finished when either: (i) LIST is
;; empty; (ii) another list is encountered; or (iii) the next
;; element in LIST is non-contiguous. Once the sublist is
;; complete, reverse it (since it's in reverse order), call
;; FUNCTION on it, and add the resulting elements, in reverse
;; order, to RESULTS.
(do ((sub (list (pop list)) (list* (pop list) sub)))
((or (endp list)
(listp (first list))
(not (funcall predicate (first sub) (first list))))
(setf result (nreconc (funcall function (nreverse sub)) result)))))))
Here's your original example:
(map-contig 'reverse '< '(1 2 (4 5) 5))
;=> (2 1 (5 4) 5)
It's worth noting that this will detect discontinuities within a single sublist. For instance, if we only want continuous sequences of integers (e.g., where each successive difference is one), we can do that with a special predicate:
(map-contig 'reverse (lambda (x y) (eql y (1+ x))) '(1 2 3 5 6 8 9 10))
;=> (3 2 1 6 5 10 9 8)
If you only want to break when a sublist occurs, you can just use a predicate that always returns true:
(map-contig 'reverse (constantly t) '(1 2 5 (4 5) 6 8 9 10))
;=> (5 2 1 (5 4) 10 9 8 6)
Here's another example where "contiguous" means "has the same sign", and instead of reversing the contiguous sequences, we sort them:
;; Contiguous elements are those with the same sign (-1, 0, 1),
;; and the function to apply is SORT (with predicate <).
(map-contig (lambda (l) (sort l '<))
(lambda (x y)
(eql (signum x)
(signum y)))
'(-1 -4 -2 5 7 2 (-6 7) -2 -5))
;=> (-4 -2 -1 2 5 7 (-6 7) -5 -2)
A more Prolog-ish approach
(defun reverse-contig (list)
(labels ((reverse-until (list accumulator)
"Returns a list of two elements. The first element is the reversed
portion of the first section of the list. The second element is the
tail of the list after the initial portion of the list. For example:
(reverse-until '(1 2 3 (4 5) 6 7 8))
;=> ((3 2 1) ((4 5) 6 7 8))"
(if (or (endp list) (listp (first list)))
(list accumulator list)
(reverse-until (rest list) (list* (first list) accumulator)))))
(cond
;; If LIST is empty, return the empty list.
((endp list) '())
;; If the first element of LIST is a list, then REVERSE-CONTIG it,
;; REVERSE-CONTIG the rest of LIST, and put them back together.
((listp (first list))
(list* (reverse-contig (first list))
(reverse-contig (rest list))))
;; Otherwise, call REVERSE-UNTIL on LIST to get the reversed
;; initial portion and the tail after it. Combine the initial
;; portion with the REVERSE-CONTIG of the tail.
(t (let* ((parts (reverse-until list '()))
(head (first parts))
(tail (second parts)))
(nconc head (reverse-contig tail)))))))
(reverse-contig '(1 2 3 (4 5) 6 7 8))
;=> (3 2 1 (5 4) 8 7 6)
(reverse-contig '(1 3 (4) 6 7 nil 8 9))
;=> (3 1 (4) 7 6 nil 9 8)
Just two notes about this. First, list* is very much like cons, in that (list* 'a '(b c d)) returns (a b c d). list** can take more arguments though (e.g., **(list* 'a 'b '(c d e)) returns (a b c d e)), and, in my opinion, it makes the intent of lists (as opposed to arbitrary cons-cells) a bit clearer. Second, the other answer explained the use of destructuring-bind; this approach could be a little bit shorter if
(let* ((parts (reverse-until list '()))
(head (first parts))
(tail (second parts)))
were replaced with
(destructuring-bind (head tail) (reverse-until list '())
You can perform all at once with a single recursive function, with the usual warning that you should favor looping constructs over recursive approaches (see below):
(defun reverse-consecutive (list &optional acc)
(etypecase list
;; BASE CASE
;; return accumulated list
(null acc)
;; GENERAL CASE
(cons (destructuring-bind (head . tail) list
(typecase head
(list
;; HEAD is a list:
;;
;; - stop accumulating values
;; - reverse HEAD recursively (LH)
;; - reverse TAIL recursively (LT)
;;
;; Result is `(,#ACC ,LH ,#LT)
;;
(nconc acc
(list (reverse-consecutive head))
(reverse-consecutive tail)))
;; HEAD is not a list
;;
;; - recurse for the result on TAIL with HEAD
;; in front of ACC
;;
(t (reverse-consecutive tail (cons head acc))))))))
Exemples
(reverse-consecutive '(1 2 (3 4) 5 6 (7 8)))
=> (2 1 (4 3) 6 5 (8 7))
(mapcar #'reverse-consecutive
'((1 3 (8 3) 2 )
(1 4 2 (3 4) 9 6 (7 8))
(1 2 (4 5) 5)))
=> ((3 1 (3 8) 2)
(2 4 1 (4 3) 6 9 (8 7))
(2 1 (5 4) 5))
Remarks
#Melye77 The destructuring-bind expression does the same thing as [Head|Tail] = List in Prolog. I could have written this instead
(let ((head (first list))
(tail (rest list)))
...)
Likewise, I prefer to use (e)typecase over the generic cond expression whenever possible, because I think it is more precise.
I could have written:
(if acc
(if (listp (first list))
(nconc ...)
(reverse-consecutive ...))
acc)
... but I think it is less clear and not a good thing to teach beginners.
On the contrary, I think it is useful, even (especially) for beginners, to introduce the full range of available constructs.
For example, overusing recursive functions is actually not recommended: there are plenty of existing iteration constructs for sequences that do not depend on the availability of tail-call optimizations (which are not guaranteed to be implemented, though it is generally available with appropriate declarations).
Iterative version
Here is an iterative version which uses of the standard reverse and nreverse functions. Contrary to the above method, inner lists are simply reversed (contiguous chunks are only detected at the first level of depth):
(defun reverse-consecutive (list)
(let (stack result)
(dolist (e list (nreverse result))
(typecase e
(list
(dolist (s stack)
(push s result))
(push (reverse e) result)
(setf stack nil))
(t (push e stack))))))

Recursive split-list function LISP

The split-list function takes a list and returns a list of two lists consisting of alternating elements of the input. I wrote the following:
(defun split-list (L)
(cond
((endp L) (list NIL NIL))
(t (let ((X (split-list (cdr L))))
(cond
((oddp (length L))
(list (cons (first L) (first X)) (cadr X)))
(t (list (first X) (cons (first L) (cadr X)))))))))
The output is as expected for odd numbered lists, the first list consisting of the 1st, 3rd, 5th etc elements and the second part consisting of the 2nd, 4th, 6th etc. With an even list however, the 1st, 2nd ,3rd.. are on the right of the returned lists with the rest on the left.
For Example:
(SPLIT-LIST '(a b c 1 2 3))
(SPLIT-LIST RETURNED ((b 1 3) (a c 2))
the order should be swapped. Is there a major flaw in my logic that I'm missing? Can I rectify this situation without making major alterations?
Yes, you can rectify the problem without major modifications.
Add a case for (endp (cdr L))
Do the recursive call on cddr L
After that, the else case will always have two new elements, one to cons onto each list; there is no more need for the length call
First, when you have cond with only one test and a default t clause, please use if instead.
Also, you are using first, but cadr; second is more readable in your context than cadr.
Now, the order is swapped for even lists. Try to perform a step-by-step execution. It might be a little tedious by hand but this is useful to understand what happens. I personally prefer to use the trace macro: (trace split-list). Then, running your example:
0: (split-list (a b c 1 2 3))
1: (split-list (b c 1 2 3))
2: (split-list (c 1 2 3))
3: (split-list (1 2 3))
4: (split-list (2 3))
5: (split-list (3))
6: (split-list nil)
6: split-list returned (nil nil)
5: split-list returned ((3) nil)
4: split-list returned ((3) (2))
3: split-list returned ((1 3) (2))
2: split-list returned ((1 3) (c 2))
1: split-list returned ((b 1 3) (c 2))
0: split-list returned ((b 1 3) (a c 2))
Unclear? Try with an odd-sized list:
0: (split-list (a b c 1 2))
1: (split-list (b c 1 2))
2: (split-list (c 1 2))
3: (split-list (1 2))
4: (split-list (2))
5: (split-list nil)
5: split-list returned (nil nil)
4: split-list returned ((2) nil)
3: split-list returned ((2) (1))
2: split-list returned ((c 2) (1))
1: split-list returned ((c 2) (b 1))
0: split-list returned ((a c 2) (b 1))
It seems you always store the innermost result in the left list!
A possible recursive implementation goes roughly like this:
(defun split-list (list)
(if (endp list)
'(nil nil)
(destructuring-bind (left right) (split-list (cddr list))
(list (cons (first list) left)
(if (second list)
(cons (second list) right)
right)))))
But this can blow the stack for sufficiently large inputs. For your information, here is a simple non-recursive approach with loop:
(defun split-list (list)
(loop for (a b) on list by #'cddr
collect a into left
when b
collect b into right
finally (return (list left right)))
And since you probably will have to split your list into more than 2 lists in your next assignment, a more generic version, still with loop:
(defun split-list (list &optional (n 2))
(loop with a = (make-array n :initial-element nil)
for e in list
for c = 0 then (mod (1+ c) n)
do (push e (aref a c))
finally (return (map 'list #'nreverse a))))
(split-list '(a b c d e f g) 3)
=> ((a d g) (b e) (c f))
If you want to have fun with circular lists, you can also try this, which works for any sequence, not only lists:
(defun split-n (sequence &optional (n 2))
(let* ((ring (make-list n :initial-element nil))
(head ring)
(last (last ring)))
(setf (cdr last) ring)
(map nil
(lambda (u)
(push u (first ring))
(pop ring))
sequence)
(setf (cdr last) nil)
(map-into head #'nreverse head)))
If you plan to investigate how this works, evaluate (setf *print-circle* t) first.
One of the very common idioms in recursive list processing is to build up result lists in reverse order, and then to reverse them just before returning them. That idiom can be useful here. The essence of your task is to return a list of two lists, the first of which should contain even-indexed elements, the second of which should contain odd-indexed elements. Here's how I'd approach this problem (if I were doing it recursively). The idea is to maintain a list of even elements and odd elements, and a boolean indicating whether we're at an even or odd position in the overall list. On each recursion, we add an element to the "evens" list, since the current index of the current list is always zero, which is always even. The trick is that on each recursive call, we swap the evens and the odds, and we negate the boolean. At the end, we use that boolean to decide which lists are the "real" evens ands odds list.
(defun split-list (list &optional (evens '()) (odds '()) (evenp t))
"Returns a list of two lists, the even indexed elements from LIST
and the odd indexed elements LIST."
(if (endp list)
;; If we're at the end of the list, then it's time to reverse
;; the two lists that we've been building up. Then, if we ended
;; at an even position, we can simply return (EVENS ODDS), but
;; if we ended at an odd position, we return (ODDS EVENS).
(let ((odds (nreverse odds))
(evens (nreverse evens)))
(if evenp
(list evens odds)
(list odds evens)))
;; If we're not at the end of the list, then we add the first
;; element of LIST to EVENS, but in the recursive call, we swap
;; the position of EVENS and ODDS, and we flip the EVENP bit.
(split-list (rest list)
odds
(list* (first list) evens)
(not evenp))))
CL-USER> (split-list '())
(NIL NIL)
CL-USER> (split-list '(1))
((1) NIL)
CL-USER> (split-list '(1 2))
((1) (2))
CL-USER> (split-list '(1 2 3))
((1 3) (2))
CL-USER> (split-list '(1 2 3 4))
((1 3) (2 4))
CL-USER> (split-list '(1 2 3 4 5 6 7 8 9 10))
((1 3 5 7 9) (2 4 6 8 10))
Recursion is always a good idea, as a conceptual tool aiding our thinking while developing a problem's solution. Once the correct code is formulated, iff your language is limited in its handling of recursion, re-write it to use other means.
A modern implementation of a Scheme-derived language (Scheme is a kind of a Lisp, right?), Racket has unlimited recursion, implementing call stack on the heap. As such, recursive code for a recursive algorithm is perfectly fine.
Correctness / serenity simplicity first, efficiency later!
The simple solution for your requirements is (in the executable "pseudocode" of Haskell)
foldr (\x [a, b] -> [x:b, a]) [[], []]
I first saw this neat trick in an old F# (IIRC) answer by user ed'ka (IIRC); quite a few years back. (But actually it appears to have been in haskellwiki since more or less forever).
Coded in direct recursive style in Scheme, it is
(define (split xs)
(cond
((null? xs) (list '() '()))
((split (cdr xs)) => (lambda (acc)
(list (cons (car xs) (cadr acc)) ; always in the first subgroup!
(car acc))))))
The list's head element must appear in the first subgroup. No need to exert ourselves trying hard to arrange for it to happen, just say it, and it happens just because you said so, all by itself, because of the magic that is recursion&hairsp;!
(split '(a b c 1 2 3))
(split '(a b c 1 2))
; '((a c 2) (b 1 3))
; '((a c 2) (b 1))
A side note: I decided to never use if again, in preference of cond, because an if's clause in itself says nothing about its activation conditions - we must count, of all things, to know which is which. With cond it's plain, and it is right there at the clause's start.
It is easy enough to amend this to produce e.g. a three-way split, with
(define (split3 xs)
(cond
((null? xs) (list '() '() '()))
(else (apply
(lambda (a b c) ; Scheme-style destructuring
(list (cons (car xs) c) ; rotate right:
a ; xs's 2nd elt to appear in the 2nd group!
b)) ; head element of (cdr xs) is in `a`
(split3 (cdr xs)))))) ; the recursive result
(split3 '(a b c 1 2 3))
(split3 '(a b c 1 2))
; '((a 1) (b 2) (c 3))
; '((a 1) (b 2) (c))

Rewrite a list with defun in Lisp

I want to write a function which outputs a list.
The function gets a list and outputs a new one. For example:
(0 0 1 2 2 1) -> (3 4 4 5 5 6)).
What it does is: the index+1 in the initial list is a value in the new list. And the that value is placed x times in the new list dependent on the value in the initial list.
(1 2) -> (1 2 2)
(0 3 0 3) -> (2 2 2 4 4 4)
So 3 is on the second position, the value is three so 2(2nd position) is placed 3 times in the new list.
I came up with this, which does not work
(defun change-list (list)
(setq newlist '(1 2 3))
(setq i 0)
(while (<= i (length list))
(if (= (nth i list) 0)
(concatenate 'list '0 'newlist)
(concatenate 'list '(i) 'newlist))
(+ i 1)
(remove 0 newlist)))
The problem is mainly the fact that it does not recognize new variables. It gave me these errors:
functions.lisp:27:26:
warning: Undefined function referenced: while
functions.lisp:31:2:
warning: Free reference to undeclared variable newlist assumed special.
warning: Free reference to undeclared variable i assumed special.
Is there someone who understands this?
We were able to solve it ourselves:
(defun change-list (a)
(loop for j from 1 to (length a) by 1 append
(loop for i from 1 to (nth (- j 1) a) by 1
collect j )))
It is part of a larger assignment, and we did not get much education on lisp, more like: do it in lisp.
Let's assume this is Common Lisp, I'll then list some problems in your code:
(defun change-list (list)
(setq newlist '(1 2 3))
SETQ does not declare variables, it just sets them.
(setq i 0)
(while (<= i (length list))
WHILE does not exist in Common Lisp.
(if (= (nth i list) 0)
(concatenate 'list '0 'newlist)
0 is not a list. Thus you can't concatenate it.
CONCATENATE does not have a side effect. What ever you do here is lost.
NEWLIST here is a symbol, not a list. Does not work.
(concatenate 'list '(i) 'newlist))
i is not a variable here. Putting it into a list will have no.
CONCATENATE does not have a side effect. What ever you do here is lost.
NEWLIST here is a symbol, not a list. Does not work.
(+ i 1)
The effect of the above is lost.
(remove 0 newlist)
The effect of the above is lost.
))
You can simplify your answer to this:
(defun change-list (list)
(loop for i in list and j from 1
append (loop repeat i collect j)))
Basically, just another way to do the same thing:
(defun change-list (x)
(let ((index 0))
(mapcon
#'(lambda (y)
(incf index)
(let ((z (car y)))
(unless (zerop z)
(make-list z :initial-element index)))) x)))
But may be useful for the purpose of learning / who knows what your professor expects.

Trying to remove duplicates of atoms specified in first list from second list

I'm trying to write a function that works like remove-duplicates, but it instead takes two lists as input, the first specifying characters for which duplication is not allowed, and the second being a list of various atoms which is to be pruned.
Currently I have this:
(defun like-remove-duplicates (lst1 lst2)
(if(member (first lst1) lst2)
(remove-if #'(lambda (a b)
(equals a b))lst1 lst2)))
I know it's not anywhere near right, but I can't figure out what I need to do to perform this function. I know I essentially need to check if the first item in list1 is in list2, and if so, remove its duplicates (but leave one) and then move onto the next item in the first list. I envisioned recursion, but it didn't turn out well. I've tried researching, but to no avail.
Any help?
CL-USER> (defun remove-duplicates-from-list (forbidden-list list)
(reduce (lambda (x y)
(let ((start (position y x)))
(if start
(remove y x :start (1+ start))
x)))
forbidden-list
:initial-value list))
REMOVE-DUPLICATES-FROM-LIST
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3))
(1 2 3)
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3 2))
(1 2 3)
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3 2 4))
(1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(1 2 1 3 2 4))
(1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 1 2 1 3 2 4))
(0 1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 2 3 2 4))
(0 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 2 2 3 4))
(0 2 3 4)
Recursion is performed by reduce (because here we have the most common recursion pattern: feed the result of previous iteration to the next) and removeing is done with the help of :start parameter, that is the offset after the first encounter (found by position) of the value being removed currently.
It's also important to account the case, when the value isn't found and position returns nil.
Something like this should work and have acceptable time-complexity (at the cost of soem space-complexity).
(defun like-remove-duplicates (only-once list)
"Remove all bar the first occurence of the elements in only-once from list."
(let ((only-once-table (make-hash-table))
(seen (make-hash-table)))
(loop for element in only-once
do (setf (gethash element only-once-table) t))
(loop for element in list
append (if (gethash element only-once-table)
(unless (gethash element seen)
(setf (gethash element seen) t)
(list element))
(list element)))))
This uses two state tables, both bounded by the size of the list of elements to include only once and should be roughly linear in the sum of the length of the two lists.
(defun remove-listed-dups (a b)
(reduce (lambda (x y) (if (and (find y a) (find y x)) x (cons y x)))
b :initial-value ()))

lisp filter out results from list not matching predicate

I am trying to learn lisp, using emacs dialect and I have a question.
let us say list has some members, for which predicate evaluates to false. how do I create a new list without those members? something like { A in L: p(A) is true }. in python there is filter function, is there something equivalent in lisp? if not, how do I do it?
Thanks
These functions are in the CL package, you will need to (require 'cl) to use them:
(remove-if-not #'evenp '(1 2 3 4 5))
This will return a new list with all even numbers from the argument.
Also look up delete-if-not, which does the same, but modifies its argument list.
If you manipulate lists heavily in your code, please use dash.el modern functional programming library, instead of writing boilerplate code and reinventing the wheel. It has every function to work with lists, trees, function application and flow control you can ever imagine. To keep all elements that match a predicate and remove others you need -filter:
(-filter (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (3 4 5)
Other functions of interest include -remove, -take-while, -drop-while:
(-remove (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (1 2)
(-take-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (1 2)
(-drop-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (3 2 1)
What is great about dash.el is that it supports anaphoric macros. Anaphoric macros behave like functions, but they allow special syntax to make code more concise. Instead of providing an anonymous function as an argument, just write an s-expression and use it instead of a local variable, like x in the previous examples. Corresponding anaphoric macros start with 2 dashes instead of one:
(--filter (> it 2) '(1 2 3 4 5)) ; (3 4 5)
(--remove (> it 2) '(1 2 3 4 5)) ; (1 2)
(--take-while (< it 3) '(1 2 3 2 1)) ; (1 2)
(--drop-while (< it 3) '(1 2 3 2 1)) ; (3 2 1)
I was looking for the very same last night and came across the Elisp Cookbook on EmacsWiki. The section on Lists/Sequences contains filtering teqniques and show how this can be done with mapcar and delq. I had to mod the code to use it for my own purposes but here is the original:
;; Emacs Lisp doesn’t come with a ‘filter’ function to keep elements that satisfy
;; a conditional and excise the elements that do not satisfy it. One can use ‘mapcar’
;; to iterate over a list with a conditional, and then use ‘delq’ to remove the ‘nil’
;; values.
(defun my-filter (condp lst)
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))
;; Therefore
(my-filter 'identity my-list)
;; is equivalent to
(delq nil my-list)
;; For example:
(let ((num-list '(1 'a 2 "nil" 3 nil 4)))
(my-filter 'numberp num-list)) ==> (1 2 3 4)
;; Actually the package cl-seq contains the functions remove-if and remove-if-not.
;; The latter can be used instead of my-filter.
Emacs now comes with the library seq.el, use seq-remove.
seq-remove (pred sequence)
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."
With common lisp, you can implement the function as follows:
(defun my-filter (f args)
(cond ((null args) nil)
((if (funcall f (car args))
(cons (car args) (my-filter f (cdr args)))
(my-filter f (cdr args))))))
(print
(my-filter #'evenp '(1 2 3 4 5)))
There are a ton of ways to filter or select stuff from a list using built-ins which are much faster than loops. The built-in remove-if can be used this way. For example, suppose I want to drop the elements 3 through 10 in list MyList. Execute the following code as an example:
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(and (>= Index 3) (<= Index 5))
)
MyList
)
)
You will get '(0 1 2 6 7 8 9).
Suppose you want to keep only elements between 3 and 5. You basically flip the condition I wrote above in the predicate.
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(or (< Index 3) (> Index 5))
)
MyList
)
)
You will get '(3 4 5)
You can use whatever you need for the predicate that you must supply to remove-if. The only limit is your imagination about what to use. You can use the sequence filtering functions, but you don't need them.
Alternatively, you could also use mapcar or mapcar* to loop over a list using some function that turns specific entries to nil and the use (remove-if nil ...) to drop nils.
It's surprising there's no builtin version of filter without cl or (or seq which is very new).
The implementation of filter mentioned here (which you see in the Elisp Cookbook and elsewhere) is incorrect. It uses nil as a marker for items to be removed, which means if you have nils in your list to start with, they're going to be removed even if they satisfy the predicate.
To correct this implementation, the nil markers need to be replaced with an uninterred symbol (ie. gensym).
(defun my-filter (pred list)
(let ((DELMARKER (make-symbol "DEL")))
(delq
DELMARKER
(mapcar (lambda (x) (if (funcall pred x) x DELMARKER))
list))))