Nick Lewycky
Nick Lewycky

Reputation: 1342

sort list of lists by length

I'm working through a Scheme tutorial which asks for an exercise using sorting, "Sort by length of lists in descending order." I wrote this solution on my own:

(define (ls-len-sort ls)
  (sort ls (lambda (x y) (> (length x) (length y)))))

but when I tested it, I didn't get the result I expected:

> (ls-len-sort '('(1) '(3 3 3) '(5 5 5 5 5) '(4 4 4 4) '(2 2)))
'('(1) '(3 3 3) '(5 5 5 5 5) '(4 4 4 4) '(2 2))

I expected '('(5 5 5 5 5) '(4 4 4 4) '(3 3 3) '(2 2) '(1)).

Sorting works, comparing list lengths works.

> (sort '(1 3 5 4 2) >)
'(5 4 3 2 1)
> (sort '(1 3 5 4 2) (lambda (x y) (< (abs (sin x)) (abs (sin y)))))
'(3 4 1 2 5)
> (> (length '(2 2)) (length '(3 3 3)))
#f
> (> (length '(4 4 4 4)) (length '(3 3 3)))
#t

but sorting a list whose elements are lists does not:

> (sort '('(1) '(3 3 3) '(5 5 5 5 5) '(4 4 4 4) '(2 2)) (lambda (x y) (> (length x) (length y))))
'('(1) '(3 3 3) '(5 5 5 5 5) '(4 4 4 4) '(2 2))

I looked up the correct answer in the tutorial, and it's token by token the same as what I wrote:

(define (sort-length ls)
  (sort ls (lambda (x y) (> (length x) (length y)))))

so I'm guessing perhaps this is a difference between Racket v8.4 [cs] vs the version of MIT-Scheme (R5RS) the tutorial is written for?

Upvotes: 0

Views: 151

Answers (1)

Martin Půda
Martin Půda

Reputation: 7568

You got this result because of bad use of quote. Quote isn't just different name for function list, it's form which doesn't evaluate its argument and returns it. Compare these two examples:

> (list 1 2 3 (+ 2 2) 5)
(1 2 3 4 5)

> '(1 2 3 (+ 2 2) 5)
(1 2 3 (+ 2 2) 5)

Sometimes result will be the same:

> (list 1 2 3 4 5)
(1 2 3 4 5)

> '(1 2 3 4 5)
(1 2 3 4 5)

When a list is quoted, all objects inside are also quoted, so you don't have to quote them twice. As you can see, results are entirely different:

> '('(1) '(3 3 3) '(5 5 5 5 5) '(4 4 4 4) '(2 2))
('(1) '(3 3 3) '(5 5 5 5 5) '(4 4 4 4) '(2 2))

> '((1) (3 3 3) (5 5 5 5 5) (4 4 4 4) (2 2))
((1) (3 3 3) (5 5 5 5 5) (4 4 4 4) (2 2))

Which variant do you want? You can compare these two with list created with list:

> (list (list 1) (list 3 3 3) (list 5 5 5 5 5) (list 4 4 4 4) (list 2 2))
((1) (3 3 3) (5 5 5 5 5) (4 4 4 4) (2 2))

When you'll use correct variant, sort will work:

(define (ls-len-sort ls)
  (sort ls < #:key length))

> (ls-len-sort '((1) (3 3 3) (5 5 5 5 5) (4 4 4 4) (2 2)))
((1) (2 2) (3 3 3) (4 4 4 4) (5 5 5 5 5))

Upvotes: 1

Related Questions