lisp filter out results from list not matching predicate - list

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))))

Related

How to fix contract violation errors in scheme DrRacket?

(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))))))

mapcar with lambda and two list as input

first, i would like to understand the difference, if there is any, in the following code:
1 (setf list1 '(1 2 3))
2 (setf list2 '(10 100))
3
4 (defun som(x y )
5 (* x y))
6
7
8 (print(mapcar #'(lambda(x)x) list1))
9 (print (mapcar #'(lambda(x)x) list1))
which returns the following:
(1 2 3)
(1 2 3)
Then i would like to understand how to do the following:
(setf list1 '(1 2 3))
(setf list2 '(10 100))
(mapcar '#+ x y)
in order to get the following:
((11 101) (12 102) (13 103)), this is, add the first item of the first list
to every item of the second list.
Of course I could, very quickly define a function which would iterate through a list and apply a mapcar to the list. I was wondering if there is any primitive which would do that.
Thanks, have a good night
Your code
(setf list1 '(1 2 3))
(setf list2 '(10 100))
(defun som(x y )
(* x y))
(print(mapcar #'(lambda(x)x) list1))
(print (mapcar #'(lambda(x)x) list1))
;; This is the same between forms you do not need the space
;; but it is more readeable to write things with spcaes and tabs
so this is how I woul write the expression
(print (mapcar #'(lambda (x) x) list1))
or you can use the function identity
(print (mapcar #'identity list1))
allways remeber that the first element of the form is a function for the evaluator
to understand this you need to get a full understanding of lambda experssions and map functions in lisp also will be useful to learn functional programming, in that case you will wirte this as quickly as you will write the iterate version
You will have other aproches, this is not one of my foavourites because the use of global variables but it should do the thick it allways remember me to the iterative version
(defparameter *list1* '(1 2 3))
(defparameter *list2* '(10 100))
(print (mapcar (lambda (x) (mapcar (lambda (y) (+ x y)) *list2*)) *list1*))

How to return same list by using reduce function in Clojure?

In DrRacket to return the list without changing by using foldr done this way:
(foldr cons '() '(1 2 3))
However in Clojure reduce is fold left so how can I do this?
First I tried this:
(reduce cons '() '(1 2 3))
=> IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
Afterward I tried this:
(reduce conj '() '(1 2 3))
=> (3 2 1)
"=>" is the output in REPL
No I don't want to read how Clojure implements reduce. I already know that. This is a more specific question. I found the answer myself, I will post it.
In your second attempt you had to "flip" the arguments passed to cons for things to work:
(reduce #(cons %2 %1) '() '(1 2 3))
=> (3 2 1)
However, as you noticed, reduce is actually a fold-left, so the first item in the original list, becomes the inner-most (or last) item in the result list. This could be handled with reverse:
(reduce (fn[a b](cons b a)) '() (reverse '(1 2 3)))
=> (1 2 3)
You can read more about why clojure 'lacks' foldr in here
I'm not that familiar with Racket, but Clojure's reduce appears to differ from Racket's foldr in two major ways:
reduce processes the list from head to tail (vs. tail to head for foldr). In this respect, reduce is similar to foldl.
reduce passes the accumulated value as the first argument to the reducing function (vs. the last argument for foldr/foldl).
The second difference is the reason for the error when using cons -- (cons '() 1) is the first call made, and 1 obviously isn't a list.
If we consider that (conj xs x) is equivalent to (cons x xs) when xs is a list, then (reduce conj '() '(1 2 3)) is equivalent to (cons 3 (cons 2 (cons 1 '()))) which might be more apparent when written as
(->> '()
(cons 1)
(cons 2)
(cons 3))
Now, if you don't mind the result being a vector instead of a list, you could do:
(reduce conj [] '(1 2 3))
Or, if you prefer, you could convert the result into a seq so that it essentially behaves like a list:
(seq (reduce conj [] '(1 2 3)))
Alternatively, you could reverse the input list:
(reduce conj () (reverse '(1 2 3)))
Here is my solution. I don't know how efficient it. We used this kind of solutions in University during Racket lessons.
(reduce #(concat %1 (list %2)) '() '(1 2 3))
=> (1 2 3)

If you're mapping a function over a list in rackect how can you get a reference to the next element?

If I have a list and I map a lambda function over it how can I get a reference to the next or previous item while processing the current one?
(map (lambda (x) x) '(1 2 3))
How would I reference the previous or next element while processing x?
John McCarthy originally made maplist and it's defined in CL still and predates map(car). It's definition in Scheme would be something like:
(define (maplist fun lst)
(if (null? lst)
'()
(cons (fun lst) (maplist fun (cdr lst)))))
(maplist values '(1 2 3 4)) ; ==> ((1 2 3 4) (2 3 4) (3 4) (4))
It's slightly more difficult to get each element like map but if you need more than the first then it's perfect.
Start with your one list, construct two other lists, one 'shifted' right, and the other 'shifted' left. Like this:
(define (process func x)
(let ((to-front (cons 'front (reverse (cdr (reverse x)))))
(to-rear (append (cdr x) (list 'rear))))
(map func to-front x to-rear)))
Note that the stuff above with reverse is because map expects all lists to have the same length. So when adding to the front, you need to remove one from the tail.
Also, the provided func needs to accept three arguments.
> (process list '(a b c))
((front a b) (a b c) (b c rear))
You can always use map on two zipped lists, i.e.
(import (srfi srfi-1)) ; or use some zip implementation
(define a '(1 2 3 4 5))
(map (lambda (x) x)
(zip a
(append (cdr a) (list (car a)))))
which results in ((1 2) (2 3) (3 4) (4 5) (5 1)).
Of course, the above assumes "periodic" boundary conditions for the lists (you should modify the boundary conditions for your case).
And also you would need to modify the lambda to handle pairs of elements.
For simplicity let's take the case of two elements at a time -- the current and next one. So if you have (list 1 2 3), and a function that takes this and next args, you want it to be called with:
1 2
2 3
3 <some value, let's say 3>
You could write that concisely as:
(map f xs (append (drop xs 1) (list (last xs))))
However the drop and append-ing means that's not the fastest way to do it. Instead you could write a map-slide-pairs function to do it more directly:
#lang racket/base
(require racket/match)
;; map a list as "sliding pairs". For example:
;; (map-slide-pairs cons '(1 2 3)) ==> '((1 . 2)
;; (2 . 3)
;; (3 . 3))
(define (map-slide-pairs f xs #:last-val [last-val #f])
;; Concise implementation:
;; (map f xs (append (drop xs 1) (list (last xs)))))
;; Faster implementation:
(let loop ([xs xs])
(match xs
[(list) (list)]
[(list this) (list (f this (or last-val this)))]
[(list this next more ...) (cons (f this next)
(loop (cons next more)))])))
(module+ test
(require rackunit)
(check-equal? (map-slide-pairs cons '(1 2 3))
'([1 . 2][2 . 3][3 . 3]))
(check-equal? (map-slide-pairs cons '(1 2 3) #:last-val 100)
'([1 . 2][2 . 3][3 . 100])))
Hopefully you can see how to extend this and make a "map-slide-triples" function that would be called with the previous, current, and next elements of the list.

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.