#lang racket

(module+ test
  (require rackunit))

(define (count-odds lst)
  (cond
    [(empty? lst) 0]
    [(odd? (first lst)) (add1 (count-odds (rest lst)))]
    [else (count-odds (rest lst))]))

(module+ test
  (check-equal? (count-odds (list 3 2 1 1 2 3 4 5 5 6)) 6))

(define (count-odds2 lst)
  (define (helper lst odds)
    (cond
      [(empty? lst) odds]
      [(odd? (first lst)) (helper (rest lst) (add1 odds))]
      [else (helper (rest lst) odds)]))
  (helper lst 0))

(module+ test
  (check-equal? (count-odds2 (list 3 2 1 1 2 3 4 5 5 6)) 6)
  (define random-list (build-list 100 (lambda (x) (random 1 100))))
  (check-equal? (count-odds random-list) (count-odds2 random-list)))

(define (count-odds3 lst)
  (for/fold
      ([odds 0])
      ([n lst])
    (cond
      [(odd? n) (add1 odds)]
      [else odds])))

(module+ test
  (check-equal? (count-odds3 (list 3 2 1 1 2 3 4 5 5 6)) 6)
  (check-equal? (count-odds random-list) (count-odds3 random-list))
  (check-equal? (count-odds3 (list 3 2 1 1 2 3 4 5 5 6)) 6))

(define big-list (range 50000000))
(for* ([fun (list count-odds count-odds2 count-odds3)]
       [rep '(1 2 3)])
  (printf "~a ~a\n" fun rep)
  (time  (fun big-list)))

;#<procedure:count-odds> 1
;cpu time: 22109 real time: 22390 gc time: 15828
;#<procedure:count-odds> 2
;cpu time: 19578 real time: 19679 gc time: 16250
;#<procedure:count-odds> 3
;cpu time: 18109 real time: 18231 gc time: 14859
;#<procedure:count-odds2> 1
;cpu time: 3125 real time: 3178 gc time: 93
;#<procedure:count-odds2> 2
;cpu time: 2765 real time: 2822 gc time: 31
;#<procedure:count-odds2> 3
;cpu time: 2765 real time: 2798 gc time: 31
;#<procedure:count-odds3> 1
;cpu time: 1000 real time: 1002 gc time: 0
;#<procedure:count-odds3> 2
;cpu time: 1187 real time: 1252 gc time: 15
;#<procedure:count-odds3> 3
;cpu time: 984 real time: 1002 gc time: 0