2013-02-17 18 views
4

我需要一個將多個值連接成(簡單)向量的函數,類似於(concatenate)。但是,不像concateate,它應該能夠處理不是向量或序列的參數。Common Lisp:將多個值連接成矢量

I.e.它應該像這樣工作:

(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不能這樣做。我不太清楚如何使用它與宏(有,@構造,將列表插入到生成的lisp表單中,但我不太清楚在這種情況下如何區分非序列和序列)。

回答

4

reduce在另一個回覆中的方法是二次方及時。

這裏是一個線性溶液

(defun my-concatenate (type &rest args) 
    (apply #'concatenate type 
     (mapcar (lambda (a) (if (typep a 'sequence) a (list a))) 
       args))) 
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) 

編輯:好,你應該接受對方的回答。

+0

請注意,這是一個**二次**算法來解決**線性**問題。 – sds 2013-02-17 18:09:54

+0

OP寫道「類似於'concatenate'」。因爲concatenate是一個非破壞性的函數,所以我提供了一個非破壞性的解決方案。如果你不需要保留原始矢量,並且你想要一個線性算法,那麼你可以在lambda中使用'append'。 – Haile 2013-02-17 18:13:34

+0

我的線性解決方案也是非破壞性的。你的解決方案的問題是你將兩個參數串聯起來。 – sds 2013-02-17 18:15:58

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" 

上面對於載體很好。列表的一個版本留作練習。