Common Lisp: concatenate multiple values into vector - common-lisp

I need a function that concatenates multiple values into (simple) vector, similar to (concatenate ). However, unlike concatenate, it should be able to handle arguments that are not vectors or sequences.
I.e. it should work like this:
(concat #(1 2) 3) => #(1 2 3)
(concat 1 2 3) => #(1 2 3)
(concat 1 #(2 3 4)) => #(1 2 3 4)
(concat #(1 2) 2 #(3 4 5)) => #(1 2 3 4 5)
How can I do this? I think I've forgotten some trivial lisp construct that makes it possible.
As far as I can tell, concatenate can't do it. and I'm not quite sure how to use make it with macro (there's ,# consturct that inserts list into resulting lisp form, but but I'm not quite sure how to distinguish between non-sequences and sequences in this case).

The reduce approach in the other reply is quadratic in time.
Here is a linear solution:
(defun my-concatenate (type &rest args)
(apply #'concatenate type
(mapcar (lambda (a) (if (typep a 'sequence) a (list a)))
args)))

Since we can compute the length of the sequence, we can allocate the result sequence and then copy the elements into it.
(defun concat (type &rest items)
(let* ((len (loop for e in items
if (typep e 'sequence)
sum (length e)
else sum 1))
(seq (make-sequence type len)))
(loop with pos = 0
for e in items
if (typep e 'sequence)
do (progn
(setf (subseq seq pos) e)
(incf pos (length e)))
else
do (progn
(setf (elt seq pos) e)
(incf pos)))
seq))
CL-USER 17 > (concat 'string "abc" #\1 "def" #\2)
"abc1def2"
Above works well for vectors. A version for lists is left as an exercise.

defun my-concatenate (type &rest vectors)
(reduce (lambda (a b)
(concatenate
type
(if (typep a 'sequence) a (list a))
(if (typep b 'sequence) b (list b))))
vectors))
You can use reduce with a little modification of #'concatenate on your arguments. If one of the arguments is not a sequence, just transform it into a list (concatenate works even with mixed arguments of simple-vectors and lists).
CL-USER> (my-concatenate 'list #(1 2 3) 3 #(3 5))
(1 2 3 3 3 5)
CL-USER> (my-concatenate 'simple-vector #(1 2 3) 3 #(3 5))
#(1 2 3 3 3 5)
CL-USER> (my-concatenate 'simple-vector 1 #(2 3) (list 4 5))
#(1 2 3 4 5)
EDIT: well, you should probably accept the other answer.

Related

Question about foldl function in Racket. (Functional programming)

So I have this line of code:
(foldl cons '() '(1 2 3 4))
And the output I get when I run it is this:
'(4 3 2 1)
Can you please explain to me why I don’t get '(1 2 3 4) instead?
I read the documentation but I am still a bit confused about how foldl works. Also if I wanted to define foldl how would I specify in Racket that the function can take a variable amount of lists as arguments?
Thanks!
Yes. By the definition of left fold, the combining function is called with the first element of the list and the accumulated result so far, and the result of that call is passed (as the new, updated accumulated result so far) to the recursive invocation of foldl with the same combining function and the rest of the list:
(foldl cons '() '(1 2 3))
=
(foldl cons (cons 1 '()) '(2 3))
=
(foldl cons (cons 2 (cons 1 '())) '(3))
=
(foldl cons (cons 3 (cons 2 (cons 1 '()))) '())
=
(cons 3 (cons 2 (cons 1 '())))
And when the list is empty, the accumulated result so far is returned as the final result.
To your second question, variadic functions in Scheme are specified with the dot . in the argument list, like so:
(define (fold-left f acc . lists)
(if (null? (first lists)) ;; assume all have same length
acc
(apply fold-left ;; recursive call
f
(apply f (append (map first lists) ;; combine first elts
(list acc))) ;; with result so far
(map rest lists)))) ;; the rests of lists
Indeed,
(fold-left (lambda (a b result)
(* result (- a b)))
1
'(1 2 3)
'(4 5 6))
returns -27.

Check consecutive numbers recursively using Lisp

I'm trying to write a recursive function to check if the elements of a list are increasing consecutively.
(defun test (lst)
(if (null lst)
1
(if (= (car lst) (1- (test (cdr lst))))
1
0)))
(setq consecutive '(1 2 3 4))
(setq non-consecutive '(2 5 3 6))
The results are:
CL-USER> (test non-consecutive)
0
CL-USER> (test consecutive)
0
(test consecutive) should return 1. How can I write this function correctly?
To check that the numbers in the sequence are consecutive, i.e.,
increasing with step 1, you need this:
(defun list-consecutive-p (list)
(or (null (cdr list))
(and (= 1 (- (second list) (first list)))
(list-consecutive-p (rest list)))))
Then
(list-consecutive-p '(1 2 3 4))
==> T
(list-consecutive-p '(1 4))
==> NIL
(list-consecutive-p '(4 1))
==> NIL
NB. Numbers are a poor substitute for booleans.
PS. I wonder if this is related to How to check if all numbers in a list are steadily increasing?...

Delete occurences of item from non-linear list

I am trying to delete all occurrences of an element from a list, from any levels of the list. I am required to use a map function though. I am using Common Lisp. For example I'd want to be able to do:
(fdelete '(1 2 3 4 (3)) 3) => (1 2 4)
What I've tried so far:
This function will do what's needed, sort of. It will replace all occurences of the given element with NIL, so it's not exactly what I want.
(defun fdelete (l e)
(cond
((null l) 0)
((equal l e) nil)
((atom l) l)
(t (mapcar (lambda(l) (fdelete l e )) l ))
)
)
This will do
(fdelete '(1 2 3 4 (3)) 3) => (1 2 NIL 4 (NIL))
My second try is with the mapcap function, since this one won't return a list the same size as the input list.
This will do what's needed, but it will 'destroy' my initial list, as in, it will bring all sublists 'to surface'.
(defun fdelete (l e)
(cond
((null l) 0)
((equal l e) nil)
((atom l) (list l))
(t(mapcan(lambda(x) (fdelete x e ))l ))
)
)
So this indeed does (fdelete '(1 2 3 4 (3)) 3) => (1 2 4)
but it will also do it wrong if I for example try this:
(fdelete '(1 2 3 (4) (3)) 3)) => (1 2 4)
I'd want it to do (fdelete '(1 2 3 (4) (3)) 3)) => (1 2 (4))
I hope my question is well formed and detailed enough, and I am providing working examples. Can someone give me a few hints on how to solve this problem?
Using mapcan is the correct choice since you can wrap in list to get a value or use nil to get item removed. For the list element, if it doesn't already match what to delete, you should check the result of the recursion and wrap it if it's not the empty list.
The solution would look something like:
(defun remove-deep (item list)
(mapcan (lambda (cur)
(cond ((equal item cur) '())
...))
list))
(remove-deep 3 '(1 nil 2 3 (3) (3 4)))
; ==> (1 nil 2 (4))
To apply the principle of least surprise I have renamed the function since delete is the destructive version of remove. Also I kept the argument order of the standard functions:

Why does the Common Lisp's apply function give a different result?

When I try this code on Emacs SLIME, the apply function gives a different result. Isn't it supposed to give the same result? Why does it give a different result? Thanks.
CL-USER> (apply #'(lambda (n)
(cons n '(b a))) '(c))
(C B A)
CL-USER> (cons '(c) '(b a))
((C) B A)
cons takes an element and a list as arguments. So (cons 'x '(a b c d)) will return (x a b c d).
apply takes a function and a list of arguments -- but the arguments will not be passed to the function as a list! They will be split and passed individually:
(apply #'+ '(1 2 3))
6
(actually, it takes one function, several arguments, of which the last must be a list -- this list will be split and treated as "the rest of the arguments to the function". try, for example, (apply #'+ 5 1 '(1 2 3)), which will return 12)
Now to your code:
The last argument you passed to the apply function is '(c), a list with one element, c. Apply will treat it as a list of arguments, so the first argument you passed to your lambda-form is c.
In the second call, you passed '(c) as first argument to cons. This is a list, which was correctly included in the first place of the resulting list: ( (c) b a).
The second call would be equivalent to the first if you did
(cons 'c '(b a))
(c b a)
And the first call would be equivalent to the second if you did
(apply #'(lambda (n) (cons n '(b a))) '((c)))
((c) b a)
CL-USER 51 > (cons '(c) '(b a))
((C) B A)
CL-USER 52 > (apply #'(lambda (n)
(cons n '(b a)))
'(c))
(C B A)
Let's use FUNCALL:
CL-USER 53 > (funcall #'(lambda (n)
(cons n '(b a)))
'(c))
((C) B A)
See also what happens when we apply a two element list:
CL-USER 54 > (apply #'(lambda (n)
(cons n '(b a)))
'(c d))
Error: #<anonymous interpreted function 40600008E4> got 2 args, wanted 1.
There is a symmetry between &rest arguments in functions and apply.
(defun function-with-rest (arg1 &rest argn)
(list arg1 argn))
(function-with-rest 1) ; ==> (1 ())
(function-with-rest 1 2) ; ==> (1 (2))
(function-with-rest 1 2 3 4 5) ; ==> (1 (2 3 4 5))
Imagine we want to take arg1 and argn and use it the same way with a function of our choice in the same manner as function-with-rest. We double the first argument and sum the rest.
(defun double-first-and-sum (arg1 &rest argn)
(apply #'+ (* arg1 2) argn))
(double-first-and-sum 1 1) ; ==> 3
(double-first-and-sum 4 5 6 7) ; ==> 26
The arguments between the function and the list of "rest" arguments are additional arguments that are always first:
(apply #'+ 1 '(2 3 4)) ; ==> (+ 1 2 3 4)
(apply #'+ 1 2 3 '(4)) ; ==> (+ 1 2 3 4)
This is very handy since often we want to add more arguments than we are passed (or else we could just have used the function apply is using in the first place. Here is something called zip:
(defun zip (&rest args)
(apply #'mapcar #'list args))
So what happens when you call it like this: (zip '(a b c) '(1 2 3))? Well args will be ((a b c) (1 2 3)) and the apply will make it become (mapcar #'list '(a b c) '(1 2 3)) which will result in ((a 1) (b 2) (c 3)). Do you see the symmetry?
Thus you could in your example you could have done this:
(apply #'(lambda (&rest n)
(cons n '(b a))) '(c))
;==> ((c) b a)
(apply #'(lambda (&rest n)
(cons n '(b a))) '(c d e))
;==> ((c d e) b a)

Position in list scheme

I'm not sure how to do this and couldn't find an example of it anywhere. How do I find the position of a value in a list. For example I have a (define findValue x lst) which accepts a value and list and from that list I want type in (findValue 3 '(1 2 0 8 5 6)) and it should return 0 since the value in position 3 is 0. From my understanding and how it usually is position 3 would be 8 and not 0 in arrays at least. How does it work in here and how do I approach this problem?
Thanks!
Try:
(define (at n xs)
(cond ((null? xs) xs)
((= n 1) (car xs))
(else (at (- n 1) (cdr xs)))))
Use it as follows:
(at 3 '(1 2 0 8 5 6)) => 0
For zero-based indexing change the (= n 1) check on the 3rd line to (= n 0).
Edit: So you want to partially apply the at function? All you need is curry and flip. They are defined as follows:
(define (curry func . args)
(lambda x (apply func (append args x))))
(define (flip func)
(lambda (a b) (func b a)))
Using curry and flip you can now partially apply at as follows:
(define position (curry (flip at) '(1 2 0 8 5 6)))
You can now use position as follows:
(position 3) => 0
(position 4) => 8
Hope that helped.
Usually indexes are counted starting from 0, and your understanding is correct. But if you're required to implement a findValue procedure that starts counting indexes from 1, it's not that hard to write the procedure:
(define (findValue idx lst)
(cond ((or (null? lst) (negative? idx)) #f)
((= idx 1) (car lst))
(else (findValue (sub1 idx) (cdr lst)))))
Explanation:
If the list received as parameter is empty or the index becomes negative, we treat that as a special case and return #f to indicate that the value was not found
If the index is 1 then we're right where we wanted, so it's time to return the current element
Otherwise advance the recursion: subtract one from the index and advance one position over the list
It works as expected:
(findValue 3 '(1 2 0 8 5 6))
=> 0
(findValue -1 '(1 2 0 8 5 6))
=> #f
(findValue 7 '(1 2 0 8 5 6))
=> #f

Resources