Common lisp 公共Lisp:将多个值连接到向量中
我需要一个将多个值连接到(简单)向量的函数,类似于Common lisp 公共Lisp:将多个值连接到向量中,common-lisp,Common Lisp,我需要一个将多个值连接到(简单)向量的函数,类似于(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) 我该怎么做?我想我忘记了一些使之成为可能的
(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构造
据我所知,concatenate做不到。我不太确定如何使用make it with macro(有,@
construct将列表插入到生成的lisp表单中,但我不太确定在这种情况下如何区分非序列和序列)
您可以在参数上稍加修改#“concatenate
。如果其中一个参数不是序列,只需将其转换为一个列表(即使使用简单向量和列表的混合参数,串联也可以工作)
编辑:嗯,你可能应该接受另一个答案。另一个回答中的
reduce
方法在时间上是二次的
下面是一个线性解决方案:
(defun my-concatenate (type &rest args)
(apply #'concatenate type
(mapcar (lambda (a) (if (typep a 'sequence) a (list a)))
args)))
因为我们可以计算序列的长度,所以我们可以分配结果序列,然后将元素复制到其中
(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"
上述方法对向量很有效。列表的版本留作练习。注意,这是一个解决线性问题的二次算法。OP写道“类似于
串联
”。因为连接是一个非破坏性的函数,所以我提供了一个非破坏性的解决方案。如果您不需要保留原始向量,并且需要线性算法,您可以在lambda中使用append
。我的线性解决方案也是无损的。您的解决方案的问题在于,您正在将参数两个接一个地连接起来。
(defun my-concatenate (type &rest args)
(apply #'concatenate type
(mapcar (lambda (a) (if (typep a 'sequence) a (list a)))
args)))
(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"