anon
anon

Reputation:

removing last element of a list(scheme)

So I have to remove the last element of a list in scheme.

For example, let's say I have a list (1 2 3 4). I need to return:

(1 2 3)

My idea:

reverse(list)
car(list)
reverse(list)

Is there a reverse function in scheme(racket)?

Upvotes: 18

Views: 39231

Answers (9)

mnemenaut
mnemenaut

Reputation: 820

(Edited: name changed; signals error on null and single element lists)

Scheme lists are mutable, so the last element of a multi-element list can be removed:

(define (remove-last-pair-from-multi-element-list! xs)
  (define who "remove-last-pair-from-multi-element-list!")
  (cond
    [(null? xs) (error who "cannot remove nonexistent pair" xs) ]
    [(not (pair? xs)) (error who "argument is not a list" xs) ]
    [(or (null? (cdr xs)) (not (pair? (cdr xs))))
     (error who "cannot remove last pair from single element list" xs) ]
    [else
     (let next-x ([p xs] [h (cdr xs)])
       (cond
         [(eq? p h) (error who "circularity in list" xs) ]
         [(or (null? (cddr p)) (not (pair? (cddr p))))
          (set-cdr! p '())
          xs ]
         [else (next-x (cdr p)
                       (if (and (pair? h) (pair? (cdr h)))
                           (cddr h)
                           xs)) ])) ]))
                      
(define was1-4 (list 1 2 3 4))
(display was1-4) (newline)
(remove-last-pair-from-multi-element-list! was1-4)
(display was1-4)

This Scheme code can be tried in DrRacket by prefixing it with:

#lang r6rs
(import (rnrs) (rnrs mutable-pairs))

For #lang racket, one could try replacing set-cdr! with an unsafe version.

Upvotes: 0

WestMountain
WestMountain

Reputation: 645

(define
  (exceptLast ls)
  (reverse (cdr (reverse ls)))
)

Upvotes: 0

Parmida Pourmatin
Parmida Pourmatin

Reputation: 31

Those who are looking for another way can check this out:

(define (removing-last xx)
(remove (list-ref xx (- (length xx) 1)) xx))

Upvotes: 1

Piroh
Piroh

Reputation: 31

I've done something simpler than: reverse(list), car(list), reverse(list) to get the last element, check out:

(define (last-one liste)
  (if(null? (cdr liste))
     null
     (cons (car liste) (last-one (cdr liste)))
  )
)

Upvotes: 2

Adrienne
Adrienne

Reputation: 2680

I would write a simple recursion, altering the typical "empty? mylist" base case to "empty? (rest mylist)," so that I can return empty when the input list is only 1 element.

(define (removelast mylist)
  (cond
    [(empty? (rest mylist)) empty]
    [(cons? mylist) (cons (first mylist) (removelast (rest mylist)))]))

(removelast (list 1 2 3 4 5))

By the way, this code is in Racket/PLT Scheme, a subset of Scheme.

Upvotes: 0

corsiKa
corsiKa

Reputation: 82589

I would do a recursive function that goes down the list and attaches the element (using cons) if the element after it is not the last, and appends nothing if it isn't.

I haven't done scheme for years though so that's as far as I can go.

Someone can run with how to implement it (unless it's homework then they probably shouldn't!)

Upvotes: 2

Tim
Tim

Reputation: 14164

There is a reverse, but using it would not be very efficient. I suggest the following recursive function.

(define (remove-last lst)
    (if (null? (cdr lst))
        '()
        (cons (car lst) (remove-last (cdr lst)))))

(remove-last '(1 2 3 4)) ; returns '(1 2 3)

The if checks whether it is at the last element of the list.

Upvotes: 10

C. K. Young
C. K. Young

Reputation: 223183

SRFI 1 (activate in Racket using (require srfi/1)) has a drop-right function:

 (drop-right '(1 2 3 4) 1)   ; => (1 2 3)

Upvotes: 10

John Clements
John Clements

Reputation: 17233

You wrote: "reverse, car, reverse". I believe you meant to write "reverse, cdr, reverse". There's nothing wrong with this solution; it's linear in the size of the list, just like any solution to this that uses the standard lists.

As code:

;; all-but-last: return the list, not including the last element
;; list? -> list?
(define (all-but-last l) (reverse (cdr (reverse l))))

If the multiple traversal of the list or the needless construction of another list copy bothers you, you can certainly avoid it, by writing the thing directly.

Given your almost-solution, I'm going to assume that this isn't homework.

Here's what it would look like, in racket:

#lang racket

(require rackunit)

;; all-but-last : return the list, except for the last element
;; non-empty-list? -> list?
(define (all-but-last l)
  (cond [(empty? l) (error 'all-but-last "empty list")]
        [(empty? (rest l)) empty]
        [else (cons (first l) (all-but-last (rest l)))]))

(check-equal? (all-but-last '(3 4 5))
              '(3 4))

Upvotes: 24

Related Questions