1

I am trying to create a scheme function that will return the shortest of its list of arguments.

(shortest '(1 2) '(2 3 4) '(4) '(5 6 7 8)) should compile (4).

This is what I have so far...

(define (shortest lst) (foldl (lambda (e r) (if (or (not r) (< e r)) e r))
     #f
     lst))

It gives error arity mismatch.

3 Answers 3

1

Your answer is close to be correct, but you need to actually compare the lengths of the sublists, and make sure that your procedure accepts a variable number of arguments. This should work, with minimum changes:

; the . is for accepting multiple args
(define (shortest . lst)
  (foldl (lambda (e r)
           ; notice how we compare the lengths
           (if (or (not r) (< (length e) (length r))) e r))
         #f
         lst))

It works as expected:

(shortest '(1 2) '(2 3 4) '(4) '(5 6 7 8))
=> '(4)

(shortest '())
=> '()

(shortest)
=> #f
Sign up to request clarification or add additional context in comments.

Comments

0

Your function has only one argument named lst, but you call it on variable number of lists. So, you should decide which input do you expect:

  1. List of lists
(define (shortest lst)
  (if (null? lst) lst
      (car (sort lst
                 (lambda (l1 l2)
                   (< (length l1) (length l2)))))))

(shortest '((1 2) (2 3 4) (4) (5 6 7 8)))
(shortest '())
  1. Variable number of lists
(define (shortest . args)
  (if (null? args) args
      (car (sort args
                 (lambda (l1 l2)
                   (< (length l1) (length l2)))))))

(shortest '(1 2) '(2 3 4) '(4) '(5 6 7 8))
(shortest '())

Comments

0

One interesting thing to ask is: can you solve this problem without taking the length of all the lists? If you have a list with a million elements and one with four, do you really need to compute the length of the huge list to know the answer?

Well, the answer is no, you don't. Here's one approach to doing this:

(define (shortest . args)
  (define (step tail-pairs new-tail-pairs)
    ;; step has a list of pairs of tail & original-list pairs it is looking at,
    ;; and another list of pairs of (cdr tail) & original-list which it will
    ;; look at on the next cycle.
    (if (null? tail-pairs)
        ;; Run out of things to look at, start on the next cycle
        (step new-tail-pairs '())
        (let ((this-tail-pair (first tail-pairs))
              (more-tail-pairs (rest tail-pairs)))
          (if (null? (car this-tail-pair))
              ;; found it: nothing left in this list so return the original
              ;; list
              (cdr this-tail-pair)
              ;; Not empty: add this tail pair with its first element removed to
              ;; the next cycle list, and loop on the remains of this cycle
              (step more-tail-pairs (cons (cons (cdr (car this-tail-pair))
                                                (cdr this-tail-pair))
                                          new-tail-pairs))))))
  ;; build the initial list of tail pairs and start stepping down it.
  (step (map cons args args) '()))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.