2013-08-04 89 views
0

假設我有名稱爲「numbers」的列表(3 1 4 5 2)。我正在尋找一個命令,將從索引0反轉到任意索引的列表,即(反向數字2),這將使新列表成爲(4 1 3 5 2)。LISP中列表中前n個元素的反向

我試過Google搜索,但無法找到合適的功能,我太多的新手在此階段自己編寫函數。

謝謝。

回答

2

您使用Lisp的哪種方言?這裏有一個解決方案(使用SRFI 1):

(require srfi/1) ; assuming you're using Racket 
(define (reverse-first-n lst n) 
    (call-with-values (lambda() 
         (split-at lst n)) 
        append-reverse!)) 

我所做的功能真正「反轉前n個元素」喜歡你的標題說,不像你的問題的描述。因此,例如:

> (reverse-first-n '(3 1 4 5 2) 2) 
'(1 3 4 5 2) 
> (reverse-first-n '(3 1 4 5 2) 3) 
'(4 1 3 5 2) 

按照要求由OP,這裏有一個Common Lisp的版本。 SDS已經發佈一個相當不錯的版本,所以我寫的版本是我計劃的解決方案更直接的端口(append-reverse!nreconc; call-with-valuesmultiple-value-call;和我移植SRFI 1的split-at到CL):

(defun split-at (list n) 
    (if (zerop n) 
     (values '() list) 
     (multiple-value-bind (prefix suffix) 
          (split-at (cdr list) (1- n)) 
     (values (cons (car list) prefix) suffix)))) 

(defun reverse-first-n (list n) 
    (multiple-value-call #'nreconc (split-at list n))) 

(爲什麼?split-at其目的是既提供takesubseq)和dropnthcdr)只有一個遍歷輸入列表中。)

+0

對不起,這是CLisp。如果我將def定義爲defun等,上面的代碼是否工作? – janvdl

+1

不,SRFI僅爲方案。我會看看我是否可以製作一個CL版本。 –

+0

好的,我添加了一個CL版本。但是因爲我沒有在CL上經驗豐富,所以它可能不是最好的解決方案。 –

6
基礎上,libary功能

簡單CL版本:

  1. 這是存儲器最佳的,即,它不會不必要地分配:
    • 不需要複製的尾部,從而nthcdr代替subseq
    • revappend拷貝其爲新鮮列表中的第一參數無論如何,所以nreconc更經濟。
  2. 這個版本是速度次優的,因爲它穿過listn個位置倍 - 一旦在subseq,一旦在nthcdr,然後在nreconc一次。

這裏是最佳的優化版本:

(defun reverse-first-n (list n) 
    (if (or (= n 0) (= n 1)) 
     list 
     (do* ((tail (list (pop list))) 
      (head tail (cons (pop list) head)) 
      (count (1- n) (1- count))) 
      ((zerop count) 
      (setf (cdr tail) list) 
      head)))) 

注意,很少有機會,這是你的代碼的性能瓶頸。我提供第二個版本的主要目的是爲了展示廣泛和精心設計的CL庫爲您節省了多少時間和精力。

+1

'nreconc'在代碼中寫錯了。驚人的多少電池包含在CL :) – Sylwester

相關問題