在LISP中反转列表的前n个元素

时间:2013-08-04 15:11:21

标签: list lisp reverse

假设我有一个名为“numbers”的列表(3 1 4 5 2)。我正在寻找一个命令,它将列表从索引0转换为任意索引,即(反向数字2),这将使新列表为(4 1 3 5 2)。

我已经尝试使用谷歌搜索,但找不到合适的功能,而且我在这个阶段自己编写这个功能太过新手了。

谢谢。

2 个答案:

答案 0 :(得分:6)

基于libary函数的简单CL版本:

(defun reverse-first-n (list n)
  (nreconc (subseq list 0 n) (nthcdr n list)))
  1. 这是内存最优的,即它不会不必要地分配:
    • 无需复制尾部,因此nthcdr代替subseq
    • revappend无论如何复制第一个参数,这是一个新的列表,因此nreconc更经济。
  2. 这个版本速度不是最理想的,因为它遍历listn位置 3 次 - 一次在subseq,一次在{{1} },然后一次进入nthcdr
  3. 这是最佳版本:

    nreconc

    请注意,这是代码中性能瓶颈的可能性很小。我提供第二个版本的主要目的是展示广泛且精心设计的CL库为您节省多少时间和精力。

答案 1 :(得分:2)

您使用的是Lisp的哪种方言?这是一个Scheme解决方案(使用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已经发布了一个相当不错的版本,所以我写的版本是我的Scheme解决方案的更直接的端口(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)提供一次输入遍历列表)。