This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-08-04
Channels
- # aleph (4)
- # bangalore-clj (1)
- # beginners (89)
- # boot (16)
- # braveandtrue (4)
- # cider (1)
- # cljs-dev (6)
- # cljsrn (90)
- # clojure (132)
- # clojure-austin (1)
- # clojure-dusseldorf (4)
- # clojure-italy (12)
- # clojure-portugal (2)
- # clojure-spec (13)
- # clojure-uk (41)
- # clojurescript (142)
- # code-reviews (19)
- # conf-proposals (1)
- # datascript (6)
- # datomic (7)
- # graphql (12)
- # jobs-discuss (3)
- # keechma (23)
- # leiningen (3)
- # lumo (22)
- # off-topic (7)
- # om (21)
- # onyx (8)
- # parinfer (46)
- # pedestal (3)
- # perun (3)
- # re-frame (10)
- # reagent (30)
- # ring (1)
- # rum (2)
- # spacemacs (1)
- # sql (2)
- # testing (17)
- # yada (32)
Could anyone help me make sure what I've done is idiomatic Clojure? I'm experienced in functional programming but not so much idiomatic Clojure style. I have a function that turns the output of a SQL query into a message board data structure (it's literally a tree). It works perfectly well, but I'd like to learn how to do it in a more Clojurian way. Snippet is here, along with example thread: https://pastebin.com/Xywtmw4z
@surgo I would be tempted to use a pair of hash-maps, one to build an adjacency list representation (key is comment id, val is direct children in a vector), and one to map from id to the full comment data, then build the tree from the leaves up - I suspect that would lead to smaller code. But nothing I see there is un-idiomatic for clojure
Alright, thanks. Mostly I was concerned by the amount of my (recur ...) usage. I kept thinking, "surely there's a function like map / reduce to do this"
actually it might be the opposite for the adjacency list - child to parent, in order to build bottom up
the sign there would be if you are consuming a sequence one end to the other
that is, for being able to use a clojure higher order function, you want sequential input consumption, which I don't think fits your code
I mean, I'm consuming the sql results one end to the other buuut the structure it's forming isn't quite as simple
right - my suggestion would start with something a lot like (let [comments (group-by :id sql-results) parents (reduce (fn [m child] (update m (:id child) (fnil conj []) (:parent child))) {} sql-results)] ...)
(clearly I am too tired to be doing this, so many edits, heh
You know, it occurs to me that I can simplify it a lot more than that due to the fact that sql results already comes both in order and with depth information. Why I didn't realize that the first time around is beyond me.
oh yeah - if you keep a hash-map tracking where to find each parent, each child is guaranteed to come after the parent and can be attached via an assoc-in
call on an accumulator in a reduce
the acc in the reduce would be something like {:node-paths {} :tree {}}
where node-paths map from an existing id, to the vector you would pass to update-in to find that item in the tree
so inserting would involve said update in, plus appending a new id at the end of a new entry in the node-paths
anyway, there is an idiom here (which is also good programming practice) of not doing multiple linear searches on a sequential input, and instead leveraging associative data structures