我需要一个将多个值连接成(简单)向量的函数,类似于(concatenate )
。但是,与连接不同,它应该能够处理不是向量或序列的参数。
即。它应该像这样工作:
(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)
我该怎么做?我想我已经忘记了一些让它成为可能的简单lisp结构。
据我所知,连接不能这样做。并且我不太确定如何使用make来创建它(有,@
个consturct将list插入到生成的lisp表单中,但是我不太确定如何在这种情况下区分非序列和序列)。
答案 0 :(得分:4)
其他回复中的reduce
方法及时为二次。
以下是线性解决方案:
(defun my-concatenate (type &rest args)
(apply #'concatenate type
(mapcar (lambda (a) (if (typep a 'sequence) a (list a)))
args)))
答案 1 :(得分:2)
由于我们可以计算序列的长度,我们可以分配结果序列,然后将元素复制到其中。
(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"
以上适用于矢量。列表的版本留作练习。
答案 2 :(得分:1)
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))
您可以在#'concatenate
上使用reduce
对您的参数进行一些修改。如果其中一个参数不是一个序列,只需将其转换为一个列表(连接甚至可以使用简单向量和列表的混合参数)。
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)
编辑:好吧,你应该接受另一个答案。