4
votes

I set myself to the task to write a Common Lisp function that concatenates two lists without using append.

Common Lisp input (concat-lists '(1 2 3) '(4 5 6)) should return (1 2 3 4 5 6)

Even though my solution seems to work it looks overtly complicated

(defun concat-lists(seq1 seq2)
    (cond ((not (null seq1)) (cons (car seq1) (concat-lists (cdr seq1) seq2)))
          (T (cond ((not (null seq2)) (cons (car seq2) (concat-lists seq1 (cdr seq2))))
                   (T nil)))))

What I'm looking for is a more elegant solution using reduce where I use seq1 as initial value and then apply a function to each element of seq2, thereby appending each value of the list to seq1. Somehow I always get stuck when trying....

Any help or input is much appreciated. Thanks!

3

3 Answers

6
votes
CL-USER 39 > (reduce #'cons
                     '(1 2 3 4 5)
                     :initial-value '(a b c d e)
                     :from-end t) 
(1 2 3 4 5 A B C D E)
4
votes

The solution of Rainer Joswig is really elegant and simple, and respects your request of using reduce.

If you want to see also a recursive, simple solution, then here is the classical one:

(defun concat-lists (seq1 seq2)
  (if (null seq1)
      seq2
      (cons (car seq1) (concat-lists (cdr seq1) seq2))))

(concat-lists '(1 2 3) '(4 5 6))
(1 2 3 4 5 6)
3
votes

I do understand your requirement for 'reduce'. and here other options:

CL also has 'concatenante'

(concatenate 'list '(1 2 3) '(4 5 6))

There is also the other less complicated (IMHO), and not as elegant.

(defun concat-lists (list1 list2) (let ((a (copy-list list1)) (b (copy-list list2))) (rplacd (last a) b) a))

or

(defun concat-lists (list1 list2) (let ((a (copy-list list1)) (b (copy-list list2))) (nconc a b)))