{"id":20983846,"url":"https://github.com/derhowie/cascade","last_synced_at":"2025-10-18T22:17:59.794Z","repository":{"id":62431361,"uuid":"79598505","full_name":"derHowie/cascade","owner":"derHowie","description":"Informs collection items with cascading data from earlier in the collection. ","archived":false,"fork":false,"pushed_at":"2017-03-22T19:53:31.000Z","size":22,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-20T07:10:04.457Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/derHowie.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-20T21:08:05.000Z","updated_at":"2017-01-21T08:59:12.000Z","dependencies_parsed_at":"2022-11-01T20:46:36.991Z","dependency_job_id":null,"html_url":"https://github.com/derHowie/cascade","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derHowie%2Fcascade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derHowie%2Fcascade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derHowie%2Fcascade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derHowie%2Fcascade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/derHowie","download_url":"https://codeload.github.com/derHowie/cascade/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243392299,"owners_count":20283560,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T05:50:29.653Z","updated_at":"2025-10-18T22:17:54.757Z","avatar_url":"https://github.com/derHowie.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cascade\n\nInforms collection items with cascading data from earlier in the collection. \n\n## Usage\n\n[![Clojars Project](https://img.shields.io/clojars/v/cascade.svg)](https://clojars.org/cascade)\n\nIn 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.\n\nHere is a simple example:\n\n```clojure\n(require '[cascade.core :refer [cascade])\n\n(cascade [1 2 3])\n;; =\u003e ([1 ()] [2 (1)] [3 (1 2)])\n```\n\nEach item in the collection receives a lazy seq of the items preceeding it.\n\nThis can be done with any data-type:\n\n```clojure\n(cascade [[1][2][3]])\n;; =\u003e ([1 ()] [2 ([1])] [3 ([1] [2])])\n\n(cascade '(#{1} #{2} #{3}))\n;; =\u003e ([#{1} ()] [#{2} (#{1})] [#{3} (#{1} #{2})])\n\n;; collections of maps receive cascade's output via the :csd key\n(cascade [{:a 1} {:a 2} {:a 3}])\n;; =\u003e ({:csd (), :a 1} {:csd ({:a 1}), :a 2} {:csd ({:a 1} {:a 2}), :a 3})\n\n;; calling cascade on a map of data works, just be aware each key-value pair in the map is treated as a vector\n(cascade {:a 1 :b 2 :c 3})\n;; =\u003e ([:a 1 ()] [:b 2 ([:a 1])] [:c 3 ([:a 1] [:b 2])])\n```\n\nOf 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:\n\n```clojure\n(cascade [{:a 1} {:a 2} {:a 3}] :a)\n;; =\u003e ({:csd (), :a 1} {:csd (1), :a 2} {:csd (1 2), :a 3})\n```\n\nCascade allows you to provide a predicate function for `reduce` if you want to reduce the seq returned by cascade.\n\n```clojure\n(defn some-predicate-fn\n  [a b]\n  (str a b))\n\n(cascade [\"a\" \"b\" \"c\" \"d\"] some-predicate-fn :reduce? true)\n;; =\u003e ([\"a\" nil] [\"b\" \"a\"] [\"c\" \"ab\"] [\"d\" \"abc\"]) \n```\n\nYou may also provide a start value when using `reduce` with cascade.\n\n```clojure\n(defn another-predicate-fn\n  [a b]\n  (* a b)\n\n(cascade '(2 5 10 1) another-predicate-fn :reduce? true :start-value 3) \n;; =\u003e ([2 3] [5 6] [10 30] [1 300]) \n```\n\n### Note:\n\nYou 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.\n\n### Example:\n\nLet's look at a slightly less contrived example to see why cascade can be useful:\n\nIn 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.\n\nHere is the data we were able to aggregate from the past 5 days of operations.\n\n```clojure\n(def cash-on-hand 100)\n(def petting-zoo-ops\n  [{:day 1\n    :patrons 24\n    :admission 7.80\n    :expenses 54.00}\n   {:day 2\n    :patrons 37\n    :admission 5.20\n    :expenses 64.00}\n   {:day 3\n    :patrons 11\n    :admission 9.00\n    :expenses 48.00}\n   {:day 4\n    :patrons 12\n    :admission 7.80\n    :expenses 10.00}\n   {:day 5\n    :patrons 26\n    :admission 6.80\n    :expenses 24.00}])\n```\n\nAt 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.\n\n```clojure\n\n(defn learn-stuff\n  [a b]\n  (let [total-patrons (+ (:patrons-to-date a)\n                         (:patrons b))\n        profit        (- (* (:patrons b)\n                            (:admission b))\n                         (:expenses b))]\n       (-\u003e a\n           (assoc :patrons-to-date total-patrons)\n           (#(assoc % :ledger-balance (+ (:ledger-balance %)\n                                         profit))))))\n\n(filter #(:csd %) (cascade\n                    petting-zoo-ops\n                    learn-stuff\n                    :reduce? true\n                    :start-value\n                    {:ledger-balance cash-on-hand\n                     :patrons-to-date 0}))\n\n;; =\u003e ({:ledger-balance 1000,\n;; =\u003e   :patrons-to-date 0}\n;; =\u003e  {:ledger-balance 1133.20\n;; =\u003e   :patrons-to-date 24}\n;; =\u003e  {:ledger-balance 1261.60\n;; =\u003e   :patrons-to-date 61}\n;; =\u003e  {:ledger-balance 1312.60\n;; =\u003e   :patrons-to-date 72}\n;; =\u003e  {:ledger-balance 1396.20\n;; =\u003e   :patrons-to-date 84})\n```\n\nWoo! Now we have a collection illustrating the state of affairs at the beginning of each day.\n\n## License\n\nCopyright © 2017 Christopher Howard\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderhowie%2Fcascade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fderhowie%2Fcascade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderhowie%2Fcascade/lists"}