sicp-ex-2.20



<< Previous exercise (2.19) | Index | Next exercise (2.21) >>


 (define (same-parity first . rest) 
   (define (same-parity-iter source dist remainder-val) 
     (if (null? source) 
         dist 
         (same-parity-iter (cdr source) 
                           (if (= (remainder (car source) 2) remainder-val) 
                               (append dist (list (car source))) 
                               dist) 
                           remainder-val))) 
    
   (same-parity-iter rest (list first) (remainder first 2))) 

mueen

Using append as above is expensive, as it will iterate through all the elements of the list you build, at _each_ iteration.

It's better simply to build the list in reverse order, and then reverse the final list at the end

 (define (same-parity first . rest) 
   (let ((yes? (if (even? first) 
                   even? 
                   odd?))) 
     (define (iter items result) 
       (if (null? items) 
           (reverse result) 
           (iter (cdr items) (if (yes? (car items)) 
                                 (cons (car items) result) 
                                 result)))) 
     (iter rest (list first)))) 
 (define (sam-parity first . rest) 
   (define (inter yes? lat) 
     (cond 
       ((null? lat) (quote())) 
       ((yes? (car lat))(cons (car lat) (inter yes? (cdr lat)))) 
       (else 
        (inter yes? (cdr lat))))) 
   (if (odd? first) 
       (inter odd? rest) 
       (inter even? rest)))  



jz

  
 ;; ex 2.20, dotted-tail notation. 
  
 (define (same-parity first . rest) 
   (define (congruent-to-first-mod-2? a) 
     (= (remainder a 2) (remainder first 2))) 
  
   (define (select-same-parity items) 
     (if (null? items)  
         items 
         (let ((curr (car items)) 
               (select-rest (select-same-parity (cdr items)))) 
           (if (congruent-to-first-mod-2? curr) 
               (cons curr select-rest) 
               select-rest)))) 
  
   (cons first (select-same-parity rest))) 
  
 ;; an alternative implementation by andras: 
 (define (same-parity a . l) 
         (define (sp-builder result tail) 
         (if (null? tail) 
         result 
         (if (even? (+ a (car tail))) 
         ;;test for same parity 
         ;;if the current beginning of the rest (car tail) is the same parity as "a", then it is appended to the result, else the result is left untouched 
         (sp-builder (append result (list (car tail))) (cdr tail)) 
         (sp-builder result (cdr tail))))) 
         (sp-builder (list a) l)) 
  
 ;; Usage: 
 (same-parity 1 2 3 4 5 6 7) 
 ;; (1 3 5 7) 
  
 (same-parity 2 3 4 5 6 7 8) 
 ;; (2 4 6 8) 
  


chris

This does it by passing the relevant test:

 (define (same-parity . l) 
   (define (parity l test) 
     (if (null? l) 
         (list) 
         (if (test (car l)) 
             (cons (car l)(parity (cdr l) test)) 
             (parity (cdr l) test)))) 
    
   (if (even? (car l)) 
       (parity l even?) 
       (parity l odd?))) 

pritesh

      
  
  
     (define (same-parity x . y) 
         ;; Finds the list of elements in y with same parity as x 
         (define (same-parity-rest y)   
             (cond  
                 ( 
                     (null? y) '() 
                 ) 
                 ( 
                 (parity-2 (car y)  x) 
                     (cons (car y) (same-parity-rest (cdr y)) )   
                 ) 
                 ( 
                     else            ;;(car y)  has  different parity than  x.. 
                     (same-parity-rest (cdr y)) 
                 ) 
             ) 
         ) 
         ;; Check if 2 integers have same parity 
         (define (parity-2 a b) 
             (= (remainder (+ a b) 2) 0)  ;; is thier sum even ? 
         ) 
         ;; Combine the result 
         (cons x (same-parity-rest y)) 
     ) 

erik

  
  
 (define (same-parity n . lst) 
    (define same-parity? (if (even? n) even? odd?)) 
    (define (iter lst acc) 
      (if (null? lst) 
          acc 
          (let ((first (car lst)) 
                (rest (cdr lst))) 
            (iter rest 
                  (if (same-parity? first) 
                      (cons first acc) 
                      acc))))) 
    (cons n (reverse (iter lst null)))) 


The footnote for this section shows a funny lambda:

  (define f (lambda (x y . z) z))
  (f 1 2 3 4 5)
  => (3 4 5)

Defining a lambda that takes a variable number of args is isn't done in the obvious way:

  (define h (lambda (. w) w))
  ;Ill-formed dotted list: (. w) ... etc, lots of errors.

This has to be defined like this:

  (define h (lambda w w))
  (h 1 2 3 4)
  => (1 2 3 4)

LisScheSic

This is shown in R5RS https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_6.html#IDX89



Shubhro

 (define (same-parity x . y) 
   (define (parity list rem) 
     (cond ((null? list) list) 
           ((= rem (remainder (car list) 2)) 
            (cons (car list) (parity (cdr list) rem) )) 
           (else 
            (parity (cdr list) rem)))) 
   (if (even? x) 
       (parity y 0) 
       (parity y 1))) 

Daniel-Amariei

Recursive process

 (define (same-parity . L) 
   (define (filter x) 
     (if (even? x) 
         even? 
         odd?)) 
   (define (construct f L) 
     (cond ((null? L) '()) 
           ((f (car L)) (cons (car L)  
                                     (construct f (cdr L)))) 
           (else (construct f (cdr L))))) 
   (construct (filter (car L)) L)) 
  
 (same-parity 2 3 4 5 6 7) ;; '(2 4 6) 

wind2412

My solution.

  (define (same-parity x . w) 
     (define (get-all w r) 
       (if (null? w) `() 
           (if (= (remainder (car w) 2) r) (cons (car w) (get-all (cdr w) r)) 
               (get-all (cdr w) r)))) 
     (cons x (get-all w (remainder x 2)))) 

It is possible to test for parity using just the sum of two terms (odd+odd=pair pair+pair=pair). Bellow Using the sum of first and each new term.

 (define (same-parity first . l)    
     (define (iter lista lfinal) 
         (if (null? lista)  
             lfinal 
             (if (even? (+ first (car lista))) 
                 (iter (cdr lista) (append lfinal (list (car lista)))) 
                 (iter (cdr lista) lfinal)))) 
     (iter l (list first))) 

acml

My recursive solution.


 (define (same-parity x . y) 
   (define (search-parity a r) 
     (if (null? r) 
         '() 
       (if (= (remainder a 2) (remainder (car r) 2)) 
           (cons (car r) (search-parity a (cdr r))) 
         (search-parity a (cdr r))))) 
   (cons x (search-parity x y))) 

ly


 (define (find-numbers items condition) 
   (if (null? items) 
       (list) 
       (if (condition (car items)) 
           (cons (car items) (find-numbers (cdr items) condition)) 
           (find-numbers (cdr items) condition)))) 
  
 (define (same-parity first . items) 
   (if (odd? first) 
       (find-numbers items odd?) 
       (find-numbers items even?))) 

Here is my solution

 (define (same-parity first . items) 
   (define (iter items) 
     (if (null? items) 
     '()  
     (if (even? (+ (car items) first)) 
         (cons (car items) (iter (cdr items))) 
         (iter (cdr items))))) 
   (cons first (iter items))) 

Evan


depaulagu

solution using filter


 (define (same-parity . l) 
   (define (first-parity) 
     (if (even? (car l)) 
         even? 
         odd?)) 
   (filter (first-parity) l)) 

stewoe

Storing the function to apply (even? or odd?) as predicate and applying it using filter


 (define (same-parity fst . rest) 
   (let ((pred (if (even? fst) even? odd?))) 
     (filter pred (cons fst rest)))) 

thongpv87

My solution using recursion


 (define (same-parity i . l) 
   (define (same-parity-i x) 
     (if (even? (+ i x)) #t #f)) 
   (cond ((null? l) i) 
         ((same-parity-i (car l)) 
          (cons i (apply same-parity l))) 
         (else (apply same-parity i (cdr l))))) 

Marisa

This solution leverages abstraction, by introducing a `sub-list` procedure that returns a subset of the input that matches a predicate. `same-parity` is defined in terms of `sub-list`.


  
 (define (sub-list predicate? x) 
   (define (sub-list-iter items result) 
     (if (null? items) (reverse result) 
         (let ((caritems (car items))) 
           (cond  
             ((predicate? caritems) 
              (sub-list-iter (cdr items) 
                             (cons caritems result))) 
             (else 
               (sub-list-iter (cdr items) result)))))) 
   (sub-list-iter x nil)) 
  
  
 (define (same-parity x . A) 
   (if (even? x)  
       (sub-list even? A) 
       (sub-list odd? A))) 

2bdkid

Works but isn't too pretty


 (define (same-parity x . y) 
   (define (filter p items) 
     (cond ((null? items) #nil) 
           ((p (car items)) (cons (car items) (filter p (cdr items)))) 
           (else (filter p (cdr items))))) 
   (let ((parity (remainder x 2))) 
     (cons x (filter (lambda (x) (= parity (remainder x 2))) y)))) 

It's surprising how many of the above solutions use functions that have not been introduced in the book at this point. Here's my solution:

 (define (same-parity . args) 
         (define (same-parity-step parity lst) 
                 (cond ((null? lst) NIL) 
                       ((= parity (remainder (car lst) 2)) (cons (car lst) (same-parity-step parity (cdr lst)))) 
                       (else (same-parity-step parity (cdr lst))) 
                 ) 
         ) 
          
         (same-parity-step (remainder (car args) 2) args) 
 ) 

LisScheSic

This is same as Shubhro's comment.



joshroybal

The way I did it.


 (define (same-parity a . b) 
   (define (iter b result) 
     (cond ((null? b) 
            (reverse result)) 
           ((or (and (even? a) (even? (car b))) 
                (and (odd? a) (odd? (car b)))) 
            (iter (cdr b) (cons (car b) result))) 
           (else 
            (iter (cdr b) result)))) 
   (iter b (list a))) 

Or non-iteratively.

 (define (same-parity a . b) 
   (define (aux b) 
     (cond ((null? b) 
            b) 
           ((or (and (even? a) (even? (car b))) 
                (and (odd? a) (odd? (car b)))) 
            (cons (car b) (aux (cdr b)))) 
           (else 
            (aux (cdr b))))) 
   (cons a (aux b))) 

yc

 (define (same-parity a . list) 
   (define (reverse list) 
     (define (iter source result) 
       (if (null? source) 
           result 
           (iter (cdr source) (cons (car source) result)))) 
     (iter list ())) 
   (define (construct test source result) 
     (if (null? source) 
         (reverse result) 
         (if (test (car source)) 
             (construct test (cdr source) (cons (car source) result)) 
             (construct test (cdr source) result)))) 
   (cons a (construct 
            (if (even? a) even? odd?) 
            list 
            '()))) 

Shun

 (define (same-parity a . b) 
   (letrec ((sp-rec (lambda (a c d) 
                      (if (not (null? c)) 
                          (if (= (modulo a 2) 0) 
                              (if (= (modulo (car c) 2) 0)     ; (modulo a 2) equals 0 
                                  (sp-rec a (cdr c) (cons (car c) d)) 
                                  (sp-rec a (cdr c) d)) 
                              (if (= (modulo (car c) 2) 1)     ; (modulo a 2) equals 1 
                                  (sp-rec a (cdr c) (cons (car c) d)) 
                                  (sp-rec a (cdr c) d))) 
                          d))) 
            (reverse (lambda (l) 
                       (letrec ((rev-rec (lambda (a b) 
                                           (if (null? a) 
                                               b 
                                               (rev-rec (cdr a) (cons (car a) b)))))) 
                         (rev-rec l (list)))))) 
     (cons a (reverse (sp-rec a b (list)))))) 

Birdy

My solution.

 (define (same-parity . l) 
   (define (helper items flag) 
     (cond ((null? items) nil) 
           ((= (remainder (car items) 2) flag) (cons (car items) (helper (cdr items) flag))) 
           (else (helper (cdr items) flag)))) 
   (cons (car l) (helper (cdr l) (remainder (car l) 2)))) 
  
 (same-parity 1 2 3 4 5 6 7) 
 (newline) 
 (same-parity 2 3 4 5 6 7) 

LisScheSic

Summary of history comments:

jz's dotted-tail notation ("implementation by andras" uses one different method to test parity based on sum remainder), chris's (uses one different interface), erik's (use let), Shubhro's (one different method to test parity based on remainder), Daniel-Amariei's, ly's, Marisa's, joshroybal's (iter same as mueen's and non-iteratively same as jz's), yc's share the same basic idea as mueen's solution.

---

The method to test parity is same as "implementation by andras": pritesh's, Evan's, thongpv87's (uses apply).

The method to test parity is same as Shubhro's: wind2412's, acml's, 2bdkid's (#nil depends on the interpreter.), Shun's (uses letrec and a bit unnecessarily complexer), Birdy's.

All the above share the same basic idea as mueen's solution.

---

depaulagu's uses the internal filter. stewoe's is based on depaulagu's and same.

---

I didn't check the detailed implementation of reverse above.



chessweb

Another solution that produces the desired results


 (define (same-parity x . r) 
   (define (parity x) 
     (if (even? x) 'even 'odd)) 
   (define (s-p x r) 
     (let ((r (if (list? (car r)) (car r) r))) 
       (cond ((null? r) (list x)) 
             (else (if (equal? (parity x) (parity (car r))) 
                       (append (same-parity x (cdr r)) (list (car r))) 
                       (same-parity x (cdr r))))))) 
   (let ((result (s-p x r))) 
     (cons (car result) (reverse (cdr result)))))