Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Common lisp 公共Lisp:将多个值连接到向量中_Common Lisp - Fatal编程技术网

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"