Suppose you have a list of lists, e.g. '(("abc" "def" "ghi") ("012" "345" "678") ("jkl" "mno" "pqr")) or '(("ab" "cd" "ef") ("01" "23" "45")).
What would be the canonical way to zip the lists inside the given list?
I.e. how would func be defined such that
(func '(("ab" "cd" "ef") ("01" "23" "45")) :sep "|" :combiner #'concat)
;; => ("ab|01" "cd|23" "ef|45")
(func '(("abc" "def" "ghi") ("012" "345" "678") ("jkl" "mno" "pqr")) ...)
;; => ("abc|012|jkl" "def|345|mno" "ghi|678|pqr")
where concat := (lambda (args) ...) is the function that combines the heads of the respective lists.
Presumably, this type of operation is known as rotation or zipMany (according to the answers for related questions for different languages).
I have something like this (double-apply)
(apply #'mapcar #'(lambda (&rest args) (apply #'concatenate 'string args)) lst)
where lst is '(("ab" "cd" "ef") ("01" "23" "45"))
for example. The combiner would be concatenate. Note that no separator is given in this example implementation.
But this seems awfully convoluted.
So, what would be a canonical implementation for this kind of operation?
For an arbitray number of lists, you'd need to get rid of apply #'mapcar, because otherwise the number of lists would be limited by call-arguments-limit.
One typical way would be to use reduce instead, combining two lists at a time:
(defun zip (list-of-lists &key (combiner #'concat))
(reduce (lambda (list-a list-b)
(mapcar combiner list-a list-b))
list-of-lists))
If you don't like the explicit lambda form, you might like curry, e. g. from alexandria:
(defun zip (list-of-lists &key (combiner #'concat))
(reduce (curry #'mapcar combiner)
list-of-lists))
Other looping constructs are loop, do, dolist, and there are also a few looping libraries, e. g. iterate, for.
Join
(defun %d (stream &rest args)
"internal function, writing the dynamic value of the variable
DELIM to the output STREAM. To be called from inside JOIN."
(declare (ignore args)
(special delim))
(princ delim stream))
(defun join (list delim)
"creates a string, with the elements of list printed and each
element separated by DELIM"
(declare (special delim))
(format nil "~{~a~^~/%d/~:*~}" list))
Goal
don't use &rest args or apply - which would limit our list lengths.
Recursive MAPCARS
(defun mapcars (f l)
(if (null (car l))
'()
(cons (funcall f (mapcar #'car l))
(mapcars f (mapcar #'cdr l)))))
Iterative MAPCARS
(defun mapcars (f l)
(loop for l1 = l then (mapcar #'cdr l1)
while (car l1)
collect (funcall f (mapcar #'car l1))))
Usage
CL-USER 10 > (mapcars (lambda (l) (join l "|")) l)
("abc|012|jkl" "def|345|mno" "ghi|678|pqr")
Your function works, but relies on APPLY.
The number of lists you can pass to apply is limited by CALL-ARGUMENTS-LIMIT, which may be large enough in a given implementation. Your function, however, is supposed to accept an arbitrary number of lists, and so, if you want to code portably, you shouldn't use apply in your case.
Zip
The zip function combines all first elements, then all second elements, etc. from a list of lists.
If your input list of lists is the following:
'((a b c d)
(0 1 2 3)
(x y z t))
Then zip will build the following list:
(list (combine (list a 0 x))
(combine (list b 1 y))
(combine (list c 2 z))
(combine (list d 3 t)))
If you look closely, you can see that you can split the work being done as mapping of the combine function over the transpose of your initial list of lists (viewed as a matrix):
((a b c d) ((a 0 x)
(0 1 2 3) ===> (b 1 y)
(x y z t)) (c 2 z)
(d 3 t))
And so, zip can be defined as:
(defun zip (combine lists)
(mapcar #'combine (transpose lists)))
Alternatively, you could use MAP-INTO, if you care about reusing the memory that is allocated when calling transpose:
(defun zip (combiner lists &aux (transposed (transpose lists)))
(map-into transposed combiner transposed))
Transpose
There are different ways to transpose a list of lists. Here I am going to use REDUCE, which is known as fold in some other functional languages. At each step of reduction, the intermediate reducing function will take a partial result and a list, and produce a new result. Our result is also a list of lists.
Below, I show the current list at each step of reduction, and the resulting list of lists.
First step
(a b c d) => ((a)
(b)
(c)
(d))
Second step
(0 1 2 3) => ((0 a)
(1 b)
(2 c)
(3 d))
Third step
(x y z t) => ((x 0 a)
(y 1 b)
(z 2 c)
(t 3 d))
Note that elements are pushed in front of each lists, which explains why each resulting list is reversed w.r.t. the expect result.
The transpose function should thus reverse each list after performing reduction:
(defun transpose (lists)
(mapcar #'reverse
(reduce (lambda (result list)
(if result
(mapcar #'cons list result)
(mapcar #'list list)))
lists
:initial-value nil)))
Like previously, it might be preferable to avoid allocating too much memory.
(defun transpose (lists)
(let ((reduced (reduce (lambda (result list)
(if result
(mapcar #'cons list result)
(mapcar #'list list)))
lists
:initial-value nil)))
(map-into reduced #'nreverse reduced)))
Example
(transpose '(("ab" "cd" "ef") ("01" "23" "45")))
=> (("ab" "01") ("cd" "23") ("ef" "45"))
(import 'alexandria:curry)
(zip (curry #'join-string "|")
'(("ab" "cd" "ef") ("01" "23" "45")))
=> ("ab|01" "cd|23" "ef|45")
Edit: the other answers already provide example definitions for join-string. You could also use the join function from cl-strings.
How about:
(defun unzip (lists &key (combiner #'list))
(apply #'mapcar combiner lists))
Then you should make join:
(defun join (l &key (sep ", "))
(format nil (format nil "~a~a~a" "~{~a~^" sep "~}") l))
Then either make a wrapper or a lambda for your specific use:
(unzip '(("abc" "def" "ghi") ("012" "345" "678") ("jkl" "mno" "pqr"))
:combiner (lambda (&rest l) (join l :sep "|")))
; ==> ("abc|012|jkl" "def|345|mno" "ghi|678|pqr")
Originally, I tried using backquote and splice ,# and defining a macro to get rid of the applys. But as #coredump pointed out, that bears then other problems.
Anyhow, you need the Pythonic function join() as a combiner, if you want to add separators between the joined elements. concatenate will make the things more complicated if the function should behave in the way you want it to.
Since I use #Sylwester's very elegant join() definition, my answer will be very similar to his. Maybe my answer is the closest to your original example.
(defun join (l &key (sep ", "))
(format nil (format nil "~a~a~a" "~{~a~^" sep "~}") l))
Using this, we can define your func to:
(defun func (lists &key (sep "|") (combiner #'join))
(apply #'mapcar
#'(lambda (&rest args) (funcall combiner args :sep sep))
lists))
Or without apply - how #Rainer Joswig points out - and all previous answerers, too - because it has restriction in number of arguments which it can take (~50):
(defun func (lists &key (sep "|") (combiner #'join))
(reduce #'(lambda (l1 l2)
(mapcar #'(lambda (e1 e2)
(funcall combiner (list e1 e2) :sep sep)) l1 l2))
lists))
Or slightly shorter:
(defun func (lists &key (sep "|") (combiner #'join))
(reduce #'(lambda (l1 l2)
(mapcar #'(lambda (&rest l) (funcall combiner l :sep sep)) l1 l2))
lists))
Testing:
(func '(("abc" "def" "ghi") ("012" "345" "678") ("jkl" "mno" "pqr")))
;; ("abc|012|jkl" "def|345|mno" "ghi|678|pqr")
Note that :sep "" makes join equivalent to the function concatenate.
(func '(("abc" "def" "ghi") ("012" "345" "678") ("jkl" "mno" "pqr")) :sep "")
;; ("abc012jkl" "def345mno" "ghi678pqr")
Thanks to #Sylwester, #coredump and #Rainer Joswig!
Why do not use the &rest in params and return that on the lambda function.
CL-USER> (mapcar (lambda (&rest l) l) '(1 2 3) '(a b c) '("cat" "duck" "fish"))
((1 A "cat") (2 B "duck") (3 C "fish"))
then you can use apply like this:
(apply #'mapcar (lambda (&rest l) l) '(("ab" "cd" "ef") ("01" "23" "45")))
; => (("ab" "01") ("cd" "23") ("ef" "45"))
until here, is what a normal zip would do, now you want to join that sublist into one string, with some custom separator.
for that the best answer is use format, and also like this answer
from stackoverflow here https://stackoverflow.com/a/41091118/1900722
(defun %d (stream &rest args)
"internal function, writing the dynamic value of the variable
DELIM to the output STREAM. To be called from inside JOIN."
(declare (ignore args)
(special delim))
(princ delim stream))
(defun join (list delim)
"creates a string, with the elements of list printed and each
element separated by DELIM"
(declare (special delim))
(format nil "~{~a~^~/%d/~:*~}" list))
Then you only need to use mapcar again on this functions and the result list from zip
(mapcar (lambda (lst) (join lst "|")) '(("ab" "01") ("cd" "23") ("ef" "45")))
; => ("ab|01" "cd|23" "ef|45")
I'm just starting to program in Common Lisp and going back through programs that I coded during some of my previous classes to learn and I am having trouble understanding the problem in my code.
(defun input-1 ()
(defvar *message* (read-line))
(defvar *a-value* (parse-integer(read-line)))
(defvar *b-value* (parse-integer(read-line))))
(defun alphabet (list " " "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m"
"n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"))
(defun alphabet-num (list 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29))
;(defun inverse (value)
; (let ((x 0))
; (loop while (< x 29)
; (print x))))
(defun inverse (value)
(dotimes (x 28)
(when (equal (mod (* x value) 29) 1)
(return-from inverse x))))
(defun get-int (string)
(getf (position string alphabet) alphabet-num))
(defun get-string (int)
(getf (position int alphabet) alphabet))
(defun cipher-calc (character)
(let ((c-int (get-int character))
(f-char ""))
(setf c-int (* *a-value* (- c-int *b-value*)))
(setf f-char (get-string (mod (abs c-int) 29)))))
However, I am getting this error
; in: DEFUN CIPHER-CALC
; (* *A-VALUE* (- C-INT *B-VALUE*))
;
; caught WARNING:
; undefined variable: *A-VALUE*
; (- C-INT *B-VALUE*)
;
; caught WARNING:
; undefined variable: *B-VALUE*
; (GET-INT CHARACTER)
;
; caught STYLE-WARNING:
; undefined function: GET-INT
; (GET-STRING (MOD (ABS C-INT) 29))
;
; caught STYLE-WARNING:
; undefined function: GET-STRING
;
; compilation unit finished
; Undefined functions:
; GET-INT GET-STRING
; Undefined variables:
; *A-VALUE* *B-VALUE*
; caught 2 WARNING conditions
; caught 2 STYLE-WARNING conditions
I find it difficult to believe that you cannot call a function inside of a let block, so I'm assuming I am making an error. Any other tips on my code would be welcome.
Your code:
(defun input-1 ()
(defvar *message* (read-line))
(defvar *a-value* (parse-integer(read-line)))
(defvar *b-value* (parse-integer(read-line))))
DEFVAR is supposed to be used on the top-level and not inside a function. In this case the variables will be defined when the function runs. But when you just compile, evaluate or load such a function, the variable is not defined. Thus the compiler will later warn that in your code these variables are undefined.
When DEFVAR is used at top-level, then Lisp will recognize that there are variable definitions.
(defvar *message*)
(defvar *a-value*)
(defvar *b-value*))
(defun input-1 ()
(setf *message* (read-line))
(setf *a-value* (parse-integer (read-line)))
(setf *b-value* (parse-integer (read-line))))
defvar doesn't do what you think it does. It ensures the variable exist and if it happens to no exist it binds it to the second argument. Thus:
(defvar *test* 5)
(defvar *test* 10) ; already exist, has no effect
*test* ; ==> 5
What you can do is define them like this on the top of your file and use setf in your function:
(defvar *message*)
(defun input-1 ()
(setf *message* (read-line))
...)
After all setting is what you are doing. You are mixing functions and variables with alphabet. Here you could use defparameter. It is like defvar but it always overwrite when you load the file:
(defparameter *alphabet* (list " " "a" "b" ...))
I am trying to create a function that sorts a given list according to the specified function I have the following code so far:
(: partition1 (All (A) ((A A -> Boolean) (Listof A) -> (Pr (Listof A) (Listof A)))))
(define (partition1 f x)
(match x
('() (Pr '() '()))
((cons hd '()) (Pr (list hd) '()))
((cons hd tl)
(match
(partition1 f tl)
((Pr A B)
(if (f hd (first tl))
(Pr (cons hd A) B)
(Pr A (cons hd B))))))))
(: quicksort1 (All (A) ((A A -> Boolean) (Listof A) -> (Listof A))))
;; sort the items according to the given order and with the quicksort algorithm
(define (quicksort1 f x)
(match x
('() '())
((cons hd tl)
(match (partition1 f tl)
((Pr A B)
(append
(quicksort1 A)
(list hd)
(quicksort1 B)))))))
My goal is to create a goal that does something like this:
> (quicksort string<? (list "a" "g" "h" "q" "w" "z" "x" "m" "n" "p"))
==> (list "a" "g" "h" "m" "n" "p" "q" "w" "x" "z")
BUT, the above function keeps giving me the following error:
match: no matching clause for '("p")
I have tried to do everything I could to eliminate this error, but in vain. I am learning programming on my own at home and would love any and all assistance! Thank you!
The problem is your partitioning function.
It should take a function of just one argument, and you use the function to classify the list elements into those for which it's true and those for which it's false.
Here's a working version in untyped Racket.
It should be easy to modify.
First, partitioning.
Note that a singleton list is not a special case.
(define (partition left? ls)
(match ls
('() (cons '() '()))
((cons hd tl)
(match
(partition left? tl)
((cons l r)
(if (left? hd)
(cons (cons hd l) r)
(cons l (cons hd r))))))))
And if we use the list's head as the pivot element, sorting could look like this:
(define (quicksort compare ls)
(match ls
('() '())
((cons hd tl)
(match (partition (lambda (x) (compare x hd)) tl)
((cons l r)
(append
(quicksort compare l)
(list hd)
(quicksort compare r)))))))
> (quicksort < '(3 4 5 2 1 7 6))
'(1 2 3 4 5 6 7)
> (quicksort string<? '("a" "g" "h" "q" "w" "z" "x" "m" "n" "p"))
'("a" "g" "h" "m" "n" "p" "q" "w" "x" "z")
> (quicksort string>? '("a" "g" "h" "q" "w" "z" "x" "m" "n" "p"))
'("z" "x" "w" "q" "p" "n" "m" "h" "g" "a")
I observed a macro expansion I do not fully understand:
(defmacro test (cons-list)
`(list
,#(mapcar #'(lambda(elem)
elem)
cons-list)))
(defmacro test-2 ()
`(list ,#(list (cons "a" "b"))))
(defmacro test-3 (cons-list)
`(list ,#cons-list))
I'd expect both macros to expand in the same fashion, as I just use mapcar in a fancy way of creating the same list again and then use that list.
But the results observed in SBCL are:
(test (list (cons "a" "b"))) expands to (LIST LIST (CONS "a" "b"))
(test-2) expands to (LIST ("a" . "b"))
(test-3 (list (cons "a" "b"))) again expands to (LIST LIST (CONS "a" "b"))
Why don't these macro expansions behave the same?
Test-2 evaluates the form (list (cons "a" "b")), the other two do not.
Remember: the arguments to a macro are the forms read, unevaluated.
In order to get the same behaviour from test-2, you would have to quote the form: ,#'(list (cons "a" "b")).
EDIT: Here is a step-by-step expansion of test:
`(list
,#(mapcar #'(lambda (elem)
elem)
cons-list))
Removing the backquote syntactic sugar:
(list* 'list (mapcar #'(lambda (elem)
elem)
cons-list)
Argument substitution in your example:
(list* 'list (mapcar #'(lambda (elem)
elem)
'(list (cons "a" "b")))
Evaluate the mapcar form:
(list* 'list '(list (cons "a" "b")))
Evaluate the `list*' form:
'(list list (cons "a" "b"))
I've been tasked with creating a function that tells the placement in numerical form of a string within a list (from left to right), so that:
(position "a" '("a" "b" "c" "d" "e"))
returns 1
(position "b" '("a" "b" "c" "d" "e"))
returns 2 and
(position "z" '("a" "b" "c" "d" "e"))
returns #f
I've written it as such:
(define (position x L)
(if (pair? L)
(if (equal? x (car L))
1
(+ 1 (position x (cdr L)))
)
#f)
)
Unfortunately,
(position "z" '("a" "b" "c" "d" "e"))
Doesn't work at all since it's trying to add #f to a number. Is there any way out of this pickle?
Your answer is correct, but I'll suggest a different approach: by using a named let for implementing tail recursion we'll obtain a more efficient solution. Also notice how using cond (instead of nesting ifs) simplifies things:
(define (position x L)
(let loop ((L L) (acc 1))
(cond ((null? L) #f)
((equal? x (car L)) acc)
(else (loop (cdr L) (add1 acc))))))
Also, in the SRFI-1 library we can find the function list-index which almost returns what you want, we just have to add one to the result to convert it to a 1-based index:
(require srfi/1)
(define (position x L)
(cond ((list-index (curry equal? x) L) => add1)
(else #f)))
I fixed it by doing:
(define (position x L)
(if (pair? L)
(if (equal? x (car L))
1
(let ((p-cdr-L (position x (cdr L))))
(if p-cdr-L
(+ 1 p-cdr-L)
#f)))
#f))