Generic Lisp: combine multiple values โ€‹โ€‹into a vector

I need a function that combines multiple values โ€‹โ€‹into a (simple) vector similar to (concatenate ) . However, unlike concatenate, it should be able to handle arguments that are not vectors or sequences.

those. It should work as follows:

 (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 forgot some trivial lisp construct that makes this possible.

As far as I can tell, concatenate cannot do this. and I'm not quite sure how to use make with a macro (there ,@ consturct, which inserts a list into the resulting lisp form, but I'm not quite sure how to distinguish between non-sequences and sequences in this case).

+4
source share
3 answers

The reduce approach in the other answer 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))) 
+4
source

Since we can calculate the length of the sequence, we can select the sequence of results 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. The list version remains as an exercise.

+2
source
 defun my-concatenate (type &rest vectors) (reduce (lambda (ab) (concatenate type (if (typep a 'sequence) a (list a)) (if (typep b 'sequence) b (list b)))) vectors)) 

You can use reduce with a slight modification of #'concatenate in your arguments. If one of the arguments is not a sequence, just convert it to 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: you should probably accept a different answer.

+1
source

All Articles