Skip to content

Instantly share code, notes, and snippets.

@soegaard
Created August 18, 2019 16:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save soegaard/be95ebdcfd140ef0e6a097852329747b to your computer and use it in GitHub Desktop.
Save soegaard/be95ebdcfd140ef0e6a097852329747b to your computer and use it in GitHub Desktop.
Uniq for Racket lists
#lang racket/base
(provide uniq)
;;;
;;; Uniq
;;;
; The function uniq takes a list as input and returns a new list:
; adjacent elements are compared and omits any repeated elements.
; In other words, uniq works like the Unix utility uniq, but on list.
; The keywords #:count, #:repeats-only? and #:uniques-only? can
; be used to change the default behaviour.
; If #:count is present the output list will contain elements
; of the form (list x frequency-of-x).
; If #:repeats-only? is present, only the repeated elements will
; be in the output.
; If #:uniques-only? is present, any repeated elements will be left out.
; > (define xs '(a a a b b c d d b b b))
; > (uniq xs)
; '(a b c d b)
; > (uniq xs #:repeats-only? #t)
; '(a b d b)
; > (uniq xs #:uniques-only? #t)
; '(c)
; > (uniq xs #:count #t)
; ((a 3) (b 2) (c 1) (d 2) (b 3))
; > (uniq xs #:count #t #:repeats-only? #t)
; '((a 3) (b 2) (d 2) (b 3))
; > (uniq xs #:count #t #:uniques-only? #t)
; '((c 1))
(require racket/list)
(define (uniq xs
#:key [=? equal?]
#:count [count? #f]
#:repeats-only? [repeats? #f] ; only inlude repeats in output
#:uniques-only? [unique? #f]) ; no repeats in output
(define msg "#:repeats-only? and #:unique-only? are mutually exclusive")
(cond
[(and repeats? unique?) (error 'unique msg)]
[(and repeats? count?) (uniq/count/repeats xs =?)]
[(and unique? count?) (uniq/count/uniques xs =?)]
[count? (uniq/count xs =?)]
[repeats? (uniq/no-count/repeats xs =?)]
[unique? (uniq/no-count/uniques xs =?)]
[else (uniq/no-count xs =?)]))
(define (uniq/no-count xs =?)
; filter out repeated elements
(cond
[(null? xs) '()]
[(null? (rest xs)) xs]
[else
(let loop ([x (first xs)]
[xs (rest xs)])
(cond
[(null? xs) (list x)]
[(=? x (first xs)) (loop x (rest xs))]
[else (cons x (loop (first xs) (rest xs)))]))]))
(define (uniq/no-count/repeats xs =?)
; filter out repeated elements,
; only output repeated elements
(cond
[(null? xs) '()]
[(null? (rest xs)) '()]
[else
(let loop ([x (first xs)]
[xs (rest xs)]
[repeated? #f])
(cond
[(null? xs) (if repeated? (list x) '())]
[(=? x (first xs)) (loop x (rest xs) #t)]
[else (if repeated?
(cons x (loop (first xs) (rest xs) #f))
(loop (first xs) (rest xs) #f))]))]))
(define (uniq/no-count/uniques xs =?)
; filter out repeated elements,
; only output unique elements
(cond
[(null? xs) '()]
[(null? (rest xs)) xs]
[else
(let loop ([x (first xs)]
[xs (rest xs)]
[unique? #t])
(cond
[(null? xs) (if unique? (list x) '())]
[(=? x (first xs)) (loop x (rest xs) #f)]
[else (if unique?
(cons x (loop (first xs) (rest xs) #t))
(loop (first xs) (rest xs) #t))]))]))
(define (uniq/count xs =?)
; filter out repeated elements
(cond
[(null? xs) '()]
[(null? (rest xs)) (list (list (first xs) 1))]
[else
(let loop ([x (first xs)]
[xs (rest xs)]
[n 1])
(cond
[(null? xs) (list (list x n))]
[(=? x (first xs)) (loop x (rest xs) (+ n 1))]
[else (cons (list x n)
(loop (first xs) (rest xs) 1))]))]))
(define (uniq/count/repeats xs =?)
; filter out repeated elements,
; only outputs repeated elements
(cond
[(null? xs) '()]
[(null? (rest xs)) '()]
[else
(let loop ([x (first xs)]
[xs (rest xs)]
[n 1])
(cond
[(null? xs) (if (= n 1) '() (list (list x n)))]
[(=? x (first xs)) (loop x (rest xs) (+ n 1))]
[else (if (= n 1)
(loop (first xs) (rest xs) 1)
(cons (list x n)
(loop (first xs) (rest xs) 1)))]))]))
(define (uniq/count/uniques xs =?)
; filter out repeated elements,
; only outputs unique elements
(map (λ (x) (list x 1))
(uniq/no-count/uniques xs =?)))
(let ()
(define xs '(1 1 1 2 2 2 3 2 2 55))
"xs"
xs
"uniq"
(uniq xs)
"uniq, repeats only"
(uniq xs #:repeats-only? #t)
"uniq, uniques only"
(uniq xs #:uniques-only? #t)
"uniq with counts"
(uniq xs #:count #t)
"uniq with counts, repeats only"
(uniq xs #:count #t #:repeats-only? #t)
"uniq with counts , uniquess only"
(uniq xs #:count #t #:uniques-only? #t))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment