Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Lisp: concatenate multiple values into vector

Tags:

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

like image 330
SigTerm Avatar asked Jan 15 '23 04:01

SigTerm


2 Answers

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)))
like image 62
sds Avatar answered Jan 30 '23 23:01

sds


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.

like image 44
Rainer Joswig Avatar answered Jan 30 '23 21:01

Rainer Joswig