Skip to content

Informs collection items with cascading data from earlier in the collection.

License

Notifications You must be signed in to change notification settings

derHowie/cascade

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cascade

Informs collection items with cascading data from earlier in the collection.

Usage

Clojars Project

In cases where the order of a collection drives a piece of your application, cascade can surface the data for each preceeding item in the collection and allow you to manipulate it.

Here is a simple example:

(require '[cascade.core :refer [cascade])

(cascade [1 2 3])
;; => ([1 ()] [2 (1)] [3 (1 2)])

Each item in the collection receives a lazy seq of the items preceeding it.

This can be done with any data-type:

(cascade [[1][2][3]])
;; => ([1 ()] [2 ([1])] [3 ([1] [2])])

(cascade '(#{1} #{2} #{3}))
;; => ([#{1} ()] [#{2} (#{1})] [#{3} (#{1} #{2})])

;; collections of maps receive cascade's output via the :csd key
(cascade [{:a 1} {:a 2} {:a 3}])
;; => ({:csd (), :a 1} {:csd ({:a 1}), :a 2} {:csd ({:a 1} {:a 2}), :a 3})

;; calling cascade on a map of data works, just be aware each key-value pair in the map is treated as a vector
(cascade {:a 1 :b 2 :c 3})
;; => ([:a 1 ()] [:b 2 ([:a 1])] [:c 3 ([:a 1] [:b 2])])

Of course, if you are interested in the data preceeding each item, you probably want to call a function on that data. Cascade allows for this:

(cascade [{:a 1} {:a 2} {:a 3}] :a)
;; => ({:csd (), :a 1} {:csd (1), :a 2} {:csd (1 2), :a 3})

Cascade allows you to provide a predicate function for reduce if you want to reduce the seq returned by cascade.

(defn some-predicate-fn
  [a b]
  (str a b))

(cascade ["a" "b" "c" "d"] some-predicate-fn :reduce? true)
;; => (["a" nil] ["b" "a"] ["c" "ab"] ["d" "abc"]) 

You may also provide a start value when using reduce with cascade.

(defn another-predicate-fn
  [a b]
  (* a b)

(cascade '(2 5 10 1) another-predicate-fn :reduce? true :start-value 3) 
;; => ([2 3] [5 6] [10 30] [1 300]) 

Note:

You may have noticed while reading these examples that the reduce function does not include the item it is appended to. I realize in a lot of cases, one may want to include that value, however I believe that type of functionality would be limiting to those who want to reduce the preceeding values then call a different function involving cascade's result and the current item.

Example:

Let's look at a slightly less contrived example to see why cascade can be useful:

In this scenario we have been contracted to build an application that helps the proprietor of a petting zoo get a better visualization of his day-to-day operations while also balancing the books.

Here is the data we were able to aggregate from the past 5 days of operations.

(def cash-on-hand 100)
(def petting-zoo-ops
  [{:day 1
    :patrons 24
    :admission 7.80
    :expenses 54.00}
   {:day 2
    :patrons 37
    :admission 5.20
    :expenses 64.00}
   {:day 3
    :patrons 11
    :admission 9.00
    :expenses 48.00}
   {:day 4
    :patrons 12
    :admission 7.80
    :expenses 10.00}
   {:day 5
    :patrons 26
    :admission 6.80
    :expenses 24.00}])

At a glance it's hard to glean a lot of information from this data, but with cascade we're only a few lines from having the information needed to fuel our data visualization components.

(defn learn-stuff
  [a b]
  (let [total-patrons (+ (:patrons-to-date a)
                         (:patrons b))
        profit        (- (* (:patrons b)
                            (:admission b))
                         (:expenses b))]
       (-> a
           (assoc :patrons-to-date total-patrons)
           (#(assoc % :ledger-balance (+ (:ledger-balance %)
                                         profit))))))

(filter #(:csd %) (cascade
                    petting-zoo-ops
                    learn-stuff
                    :reduce? true
                    :start-value
                    {:ledger-balance cash-on-hand
                     :patrons-to-date 0}))

;; => ({:ledger-balance 1000,
;; =>   :patrons-to-date 0}
;; =>  {:ledger-balance 1133.20
;; =>   :patrons-to-date 24}
;; =>  {:ledger-balance 1261.60
;; =>   :patrons-to-date 61}
;; =>  {:ledger-balance 1312.60
;; =>   :patrons-to-date 72}
;; =>  {:ledger-balance 1396.20
;; =>   :patrons-to-date 84})

Woo! Now we have a collection illustrating the state of affairs at the beginning of each day.

License

Copyright © 2017 Christopher Howard

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

About

Informs collection items with cascading data from earlier in the collection.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published