【问题标题】:How to delete the first and last elements of a list?如何删除列表的第一个和最后一个元素?
【发布时间】:2017-09-09 19:24:43
【问题描述】:

我正在尝试删除 Racket 中列表的第一个和最后一个元素。有没有其他方法可以代替:

(cdr (reverse (cdr (reverse my-list))))

【问题讨论】:

    标签: list scheme racket


    【解决方案1】:

    这是一种方法,使用 Racket 的内置程序:

    (define my-list '(1 2 3 4 5 6 7 8 9 10))
    
    (drop-right (rest my-list) 1)
    => '(2 3 4 5 6 7 8 9)
    

    注意:我们可以使用cdr 来代替rest,但rest 在Racket 中更为惯用。对于更通用的解决方案:

    ; remove `left` number of elements elements from the left side
    ; and `right` number of elements from the right side of the list
    (define (trim lst left right)
      (drop-right (drop lst left) right))
    
    (trim my-list 1 1)
    => '(2 3 4 5 6 7 8 9)
    
    (trim my-list 2 4)
    => '(3 4 5 6)
    

    【讨论】:

      【解决方案2】:

      您提出的方法使用了一些内存,因为当您再次反转它时,它会占用在该过程中丢弃的 n 个单元格。然而 Óscars 解决方案也包含 n 个细胞,因此它可能有助于清晰,但它肯定不会做得更快。

      在 500 万个元素列表上,编译(在我的机器上)大约需要 1.6 秒,这主要是 gc 时间。如果你发现你有性能问题并且你正在编写方案(不是球拍语言),你可以通过一次手动尾递归取模将其速度提高 4 倍(400 毫秒):

      #!r6rs
      (import (rnrs)
              (rnrs mutable-pairs))
      
      (define (middle lst)
        (define head (list 1))
        (let loop ((tail head) (lst (cdr lst)))
          (if (and (pair? lst) (pair? (cdr lst)))
              (begin 
                (set-cdr! tail (list (car lst)))
                (loop (cdr tail) (cdr lst)))
              (cdr head))))
      

      如您所见,它非常难看,因此您必须真的想要更高的性能才能用它替换 2 个反向和 2 个 cdr。

      【讨论】: