red_trumpet
red_trumpet

Reputation: 611

How to delete the first and last elements of a list?

I'm trying to remove both the first and the last elements of a list in Racket. Is there some other way of doing this instead of:

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

Upvotes: 2

Views: 2374

Answers (2)

Óscar López
Óscar López

Reputation: 236140

Here's one way to do it, using Racket's built-in procedures:

(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)

Note: we can use cdr instead of rest, but rest is more idiomatic in Racket. For a more general solution:

; 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)

Upvotes: 2

Sylwester
Sylwester

Reputation: 48775

The method you present uses some memory since it cons n cells that are thrown away in the process when you again reverse it. However Óscars solution also cons n cells so it may help clarity it certainly won't do it faster.

On a 5 million element list it takes about 1,6 seconds when compiled (on my machine) and that is mostly gc time. If you find you have performance problems and you are writing scheme (not racket language) you can get it 4 times faster (400ms) by doing one pass manual tail recursive modulo cons:

#!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))))

As you can see it's quite ugly so you must really want more performance to replace 2 reverses and 2 cdrs with this.

Upvotes: 0

Related Questions