Ats
Ats

Reputation: 169

Compare odd and even numbers in a list in scheme

I'm trying make an iterative procedure which compare every odd and every even elements in a list. Every odd number should be odd and every even should be even. First number must be odd. Output should be like this:

(odd-even-args? 1 2 3 4 5) --> #t
(odd-even-args? 1 2 4 4 5) --> #f
(odd-even-args? 1 0 1) --> #t

I tried to compare two element with this: (and (odd? (car lst)) (even? (cadr lst)), but I don't know how to continue with (cddr lst).

Upvotes: 4

Views: 2032

Answers (5)

Robert Fisher
Robert Fisher

Reputation: 598

As an exercise, I wrote a version using SRFI-1 and fold:

(define (odd-even-args? . xs)
  (first
    (fold
      (lambda (x data)
        (let ((result (first data))
              (count (second data)))
          (list
            (and
              ((if
                 (odd? count)
                 odd?
                 even?)
               x)
              result)
            (+ 1 count))))
      '(#t 1)
      xs)))

Upvotes: 0

WorBlux
WorBlux

Reputation: 1413

Why not design the general case as a higher order function and implement odd-even? as a special case? that way you can also implement even-odd?, or square?-tan?, or prime?-carmicheal? quite easily.

(define (predx?-predy? predx predy)
 (lambda L
  (let loop ((lst L) (pred?1 predx) (pred?2 predy))
   (if (null? lst)
       #t
       (and (pred?1 (car lst)) (loop (cdr lst) pred?2 pred?1)))))) 
 ;;flip  preds each recursion

(define odd-even? (predx?-predy? odd? even?))

(define even-odd? (predx?-predy? even? odd?))

(define square-tan (predx?-predy? square? tan?))

(define prime?-Carmichael? (predx?-predy? prime? (lambda (x) (and (not (prime? x)) (fermat-prime? x)))))

Upvotes: 0

Bwmat
Bwmat

Reputation: 4578

(define (range start end)
  (if (>= start end)
      nil
      (cons start (range (+ start 1) end)))

(define (odd-even-args? . args)
  (apply and
         (map (lambda (value index)
                      (eqv? (even? index)
                            (even? value)))
              args
              (range 1 (+ 1 (length args))))))

Upvotes: 0

Óscar López
Óscar López

Reputation: 236004

Here's one possibility: traverse all the list, asking if each element satisfies the appropriate predicate (either even? or odd?) and alternate between the predicates:

(define (odd-even-args? . lst)
  (let loop ((lst lst)
             (is-odd? #t))
    (if (null? lst)
        #t
        (and ((if is-odd? odd? even?) (car lst))
             (loop (cdr lst) (not is-odd?))))))

The answer above uses an and with the recursive call in a tail position, so it's iterative - and it's similar to the way you were thinking about the solution. Here's another solution which shows more explicitly that this is indeed an iterative process:

(define (odd-even-args? . lst)
  (let loop ((lst lst)
             (is-odd? #t))
    (cond ((null? lst) #t)
          (((if is-odd? even? odd?) (car lst)) #f)
          (else (loop (cdr lst) (not is-odd?))))))

And yet another solution, using boolean connectors instead of conditional expressions:

(define (odd-even-args? . lst)
  (let loop ((lst lst)
             (is-odd? #t))
    (or (null? lst)
        (and ((if is-odd? odd? even?) (car lst))
             (loop (cdr lst) (not is-odd?))))))

Upvotes: 5

Nikolai Popov
Nikolai Popov

Reputation: 5675

Just another variant ( probably not good one .. )

(define (odd-even-args? . args)
  (define (iter lst)
    (cond ((null? lst) #t)
          ((null? (cdr lst)) (odd? (car lst)))
          ((and (odd? (car lst)) (even? (cadr lst))) (iter (cddr lst)))
          (else #f)))
  (iter args))

Upvotes: 2

Related Questions