假設我有名稱爲「numbers」的列表(3 1 4 5 2)。我正在尋找一個命令,將從索引0反轉到任意索引的列表,即(反向數字2),這將使新列表成爲(4 1 3 5 2)。LISP中列表中前n個元素的反向
我試過Google搜索,但無法找到合適的功能,我太多的新手在此階段自己編寫函數。
謝謝。
假設我有名稱爲「numbers」的列表(3 1 4 5 2)。我正在尋找一個命令,將從索引0反轉到任意索引的列表,即(反向數字2),這將使新列表成爲(4 1 3 5 2)。LISP中列表中前n個元素的反向
我試過Google搜索,但無法找到合適的功能,我太多的新手在此階段自己編寫函數。
謝謝。
您使用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-values
⇒multiple-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
其目的是既提供take
(subseq
)和drop
(nthcdr
)只有一個遍歷輸入列表中。)
簡單CL版本:
list
到n
個位置倍 - 一旦在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庫爲您節省了多少時間和精力。
'nreconc'在代碼中寫錯了。驚人的多少電池包含在CL :) – Sylwester
對不起,這是CLisp。如果我將def定義爲defun等,上面的代碼是否工作? – janvdl
不,SRFI僅爲方案。我會看看我是否可以製作一個CL版本。 –
好的,我添加了一個CL版本。但是因爲我沒有在CL上經驗豐富,所以它可能不是最好的解決方案。 –