4

我需要一个将多个值连接成(简单)向量的函数,类似于(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 结构。

据我所知,连接不能做到这一点。而且我不太确定如何将它与宏一起使用(有,@将列表插入结果lisp形式的构造,但我不太确定在这种情况下如何区分非序列和序列)。

4

3 回答 3

5

reduce另一个答复中的方法是时间二次方

这是一个线性解决方案:

(defun my-concatenate (type &rest args)
  (apply #'concatenate type
         (mapcar (lambda (a) (if (typep a 'sequence) a (list a)))
                 args)))
于 2013-02-17T18:14:13.293 回答
3

由于我们可以计算序列的长度,我们可以分配结果序列,然后将元素复制到其中。

(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"

以上适用于向量。列表版本留作练习。

于 2013-02-17T19:16:00.000 回答
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))

你可以对你的论点reduce进行一点修改。#'concatenate如果其中一个参数不是序列,只需将其转换为列表(即使使用简单向量和列表的混合参数,连接也有效)。

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)

编辑:好吧,您可能应该接受其他答案。

于 2013-02-17T17:42:32.123 回答