Joseph
Joseph

Reputation: 61

Scheme: How to check if all elements of a list are identical

I'd like to create a Scheme function that yields true if it is passed a list that is composed entirely of identical elements. Such a list would be '(1 1 1 1). It would yield false with something like '(1 2 1 1).

This is what I have so far:

    (define (list-equal? lst)
      (define tmp (car lst))
      (for-each (lambda (x) 
                   (equal? x tmp))
                 lst)
      )

Clearly this is incorrect, and I'm new to this. I guess I'm unable to express the step where I'm supposed to return #t or #f.

Thanks in advance!

EDIT: I fiddled a bit and found a solution that seems to work very well, and with a minimal amount of code:

(define (list-equal? lst)
 (andmap (lambda (x) 
        (equal? x (car lst)))
      lst))

Thanks again for the help everyone.

Upvotes: 6

Views: 9218

Answers (10)

mepo
mepo

Reputation: 1

Yet another solution:

(define (all-same ls)
    (cond
     ((or (null? ls)
          (null? (cdr ls))) #t)
     (else (and (equal? (car ls) (next ls))
                (all-same (cdr ls)))))))

(define (next ls)
    (cond
     ((or (null? ls)
          (null? (cdr ls))) '())
     (else (cadr ls)))))

Upvotes: 0

Majora320
Majora320

Reputation: 1351

A short, concise solution:

#lang racket
(define (all-equal? lst)
  (for/and
      ([i (in-permutations lst)])
    (equal? (first i) (second i))))

; TEST CASES

(require rackunit)

(check-false (all-equal? '(1 2 3)))
(check-true (all-equal? '(1 1 1)))
(check-true (all-equal? '()))

Note that this uses racket, so this may not work with your scheme implementation.

Upvotes: 0

Lorenz Forvang
Lorenz Forvang

Reputation: 265

The andmap solution is nice, but if andmap is not available, you can use this. It uses basic operations (and, or, null check, equality check) and handles empty lists and one element lists. Similar to Sean's implementation, but no helper definition is necessary.

(define (list-equal? args)
  (or (or (null? args)
          (null? (cdr args)))
      (and (eq? (car args) (cadr args))
           (list-equal? (cdr args)))))

Upvotes: 2

andrykonchin
andrykonchin

Reputation: 2517

Minimal amount of code, if you don't care that it only works for numbers:

(define (list-equel? lst)
  (apply = lst))

Examples:

> (list-equel? '(1 1 2 1))
#f
> (list-equel? '(1 1 1 1))
#t
> (list-equel? '(1))
#t

Upvotes: 3

C. K. Young
C. K. Young

Reputation: 223023

The other answers in this thread all seem too complicated (I read through them all), so here's my take on it:

(define (all-equal? lst)
  (define item (car lst))
  (let next ((lst (cdr lst)))
    (cond ((null? lst) #t)
          ((equal? item (car lst)) (next (cdr lst)))
          (else #f))))

(It does not work with an empty list, by design. It's easy to add a (if (null? lst) #t ...) if necessary.)

Upvotes: 0

JasonFruit
JasonFruit

Reputation: 7875

Something like this should work:

(define (list-equal? lst)
  (cond ((< (length lst) 2) #t)
        (#t (and (equal? (car lst) (cadr lst))
             (list-equal? (cdr lst))))))

Upvotes: 0

Patrik
Patrik

Reputation: 855

For is bad in these languages. Try

(define list-equal?
 (lambda (lst)
   (if (= lst null)
   (true)
   (foldr = (car lst) (cdr lst))
)))

Upvotes: -1

Daniel
Daniel

Reputation: 6755

(define (list-equal? lst)
    (if (= (cdr lst) null)
        true
        (and (equal? (car lst) (cadr lst))
             (list-equal? (cdr lst)))))

Upvotes: 0

sepp2k
sepp2k

Reputation: 370162

In R6RS there's the for-all function, which takes a predicate and a list, and returns #t if the predicate returns true for all elements in the list and #f otherwise, which is exactly what you need here.

So if you're using R6RS (or any other scheme dialect that has the for-all function), you can just replace for-each with for-all in your code and it will work.

Upvotes: 0

Sean Devlin
Sean Devlin

Reputation: 1692

Try something like this:

(define (list-equal? lst)
 (define (helper el lst)
  (or (null? lst)
      (and (eq? el (car lst))
           (helper (car lst) (cdr lst)))))
 (or (null? lst)
     (helper (car lst) (cdr lst))))

This might not be the cleanest implementation, but I think it will correctly handle the cases of empty lists and one-element lists.

Upvotes: 0

Related Questions