Skip to content

Instantly share code, notes, and snippets.

@ejackson
Created June 4, 2010 09:41
Show Gist options
  • Save ejackson/425214 to your computer and use it in GitHub Desktop.
Save ejackson/425214 to your computer and use it in GitHub Desktop.
(ns
#^{:doc "New definitions for a timeseries type"}
esjtools.ts
(:use clojure.test)
(:import (clojure.lang PersistentTreeSet)))
;;----------------------------------------------------------------------------
(defprotocol Trim
"Trim a timeseries. There are performance advantages to having older+newer
rather than just trim in most implementations."
(trim-older [ts snip])
(trim-newer [ts snip]))
;;----------------------------------------------------------------------------
(deftype Timeseries [dataset]
Object
(equals [this o]
(or (identical? this o)
(and (.isInstance Timeseries o)
(= dataset (.dataset ^Timeseries o)))))
(hashCode [this]
(hash dataset))
(toString [this]
(str dataset))
;;--------------
clojure.lang.IPersistentCollection
(cons [this a]
(Timeseries. (conj dataset a)))
(empty [this]
(Timeseries. (-> dataset empty)))
;; How does this differ from equals
(equiv [this o]
(.equals this o))
(seq [this]
(seq dataset))
;;--------------
clojure.lang.IPersistentStack
(peek [this]
(-> dataset rseq first))
(pop [this]
(Timeseries. (disj dataset (peek this))))
;;--------------
clojure.lang.Sorted
(comparator [this]
(.comparator dataset))
(entryKey [this entry]
(.entryKey dataset entry))
(seq [this ascending]
(.seq dataset ascending))
(seqFrom [this key ascending]
(.seqFrom dataset key ascending))
;;--------------
Trim
(trim-older [this snip]
(Timeseries. (reduce disj dataset (subseq this < snip))))
(trim-newer [this snip]
(Timeseries. (reduce disj dataset (rsubseq this > snip)))))
;;---------------------------------------------------------------------------
;; Extra API
(defn ts [xs]
(Timeseries. (apply sorted-set xs)))
;;---------------------------------------------------------------------
;; Tests below
(deftest interface-test
(let [a (ts [1 2 3])
b (ts [1 2 3])
c (ts [1 2])
d (ts [1])
e (ts [])
f (ts [2 3])
g (ts [3])]
(testing "Testing conj..."
(are [y] (= a y)
(conj c 3)
(conj e 1 2 3)))
(testing "Testing peek..."
(are [x y] (= x y)
3 (peek a)
2 (peek c)
nil (peek e)))
(testing "Testing subseq..."
(are [x y z] (= x (subseq a y z))
[1 2 3] > -2
[1 2 3] > 0
[2 3] > 1
[1 2 3] >= 1
nil > 3 ;; Technically this should be []
nil > 4
[1 2 3] < 4
[1 2 3] <= 3
[1 2] < 3
[] < 0))
(testing "Testing rsubseq..."
(are [x y z] (= x (rsubseq a y z))
[3 2 1] > -2
[3 2 1] > 0
[3 2] > 1
[3 2 1] >= 1
[] > 3
[] > 4
[3 2 1] < 4
[3 2 1] <= 3
[2 1] < 3
nil < 0)) ;; Technically this should be []
;; trim
(testing "Testing trim..."
(are [x y] (= (Timeseries. (apply sorted-set x)) (trim-older a y))
[1 2 3] 0
[1 2 3] 1
[2 3] 2
[3] 3
[] 4)
(are [x y] (= (Timeseries. (apply sorted-set x)) (trim-newer a y))
[] 0
[1] 1
[1 2] 2
[1 2 3] 3
[1 2 3] 4))))
(deftest internal-tests
(let [a (ts [1 2 3])
b (ts [1 2])
c (ts [1 2 3])
d (ts [1])
e (ts [])]
(testing "Testing Object Interface..."
(are [x y] (= x y)
a a
a c)
(are [x y] (not (.equals x y))
a b
b a)
;; hashCode
(are [x y] (= (.hashCode x) (.hashCode y))
a a
a c)
;; toString
(is (= (.toString a) (.toString c))))
(testing "clojure.lang.IPersistentCollection..."
;; Check the basic functionality
(are [x y] (.equals x y)
a (.cons b 3)
e (.empty a)
(seq [1 2 3]) (seq a))
;; Type check these functions
(are [x] (= (type e) (type x))
(.cons b 3)
(.empty a)))
(testing "clojure.lang.IPersistentStack..."
;; Check the basic functionality
(are [x y] (= x y)
3 (.peek a)
b (.pop a)
d (-> a .pop .pop)
;; Empties and nils
nil (.peek e)
e (.pop e))
;; Type check these functions
(are [x] (= (type e) (type x))
(.pop a)))
(testing "Sorted..."
(are [x y] (= x y)
(.seq a true) (seq a)
(.seq a true) (seq [1 2 3])
(.seq a false) (seq [3 2 1])
(.seqFrom a 2 true) (seq [2 3])
(.seqFrom a 2 false) (seq [2 1])))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment