This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-08-15
Channels
- # admin-announcements (3)
- # architecture (2)
- # beginners (54)
- # boot (85)
- # braveandtrue (8)
- # cider (21)
- # cljs-dev (56)
- # cljs-site (5)
- # cljsjs (15)
- # cljsrn (9)
- # clojars (4)
- # clojure (99)
- # clojure-austin (1)
- # clojure-russia (36)
- # clojure-spec (53)
- # clojure-uk (29)
- # clojurescript (161)
- # datomic (8)
- # hoplon (3)
- # immutant (48)
- # jobs (1)
- # jobs-rus (1)
- # leiningen (10)
- # om (23)
- # om-next (1)
- # onyx (22)
- # parinfer (3)
- # planck (13)
- # protorepl (8)
- # re-frame (46)
- # reagent (2)
- # remote-jobs (1)
- # respo (1)
- # specter (5)
- # testing (12)
- # untangled (50)
- # yada (13)
Need help extending the following code to accommodate some extra logic which will affect the result. Here's the current code:
(let [facts #{:a :b :d :e}
dependencies {:m #{:e :k :d}, :c #{:b :a}, :f #{:e :c :d}}]
(map first (filter (comp #(set/subset? % facts) last) dependencies )))
=> (:c)
What I want is that when the subset
finds a match, the corresponding key (in this case :c
) needs to be added onto the facts
and the whole mapping phase will need to re-occur, thus resulting in (:c :f)
output. How would I express such state change in code? Thanks!
so basically I want - when the subset function returns 'yes' for its check to stick the :c
onto the facts
set which will need to make the filtering/mapping to repeat at which point the #{:e :c :d}
will also get satisfied (and the :f
will be added to the result (as well is to the facts
)
basically I want a mechanism to keep updating the state of the facts
until the final solution is reached
Something like this?
(first ; At the end, get acc from the vector
(reduce (fn [[acc facts] [k v]] ; Each pass through, k and v will be a key and value from the map
(if (set/subset? v facts) ; If v is a subset of facts
[(conj acc k) (conj facts k)] ; Add k to both acc and facts
[acc facts])) ; Else pass them through unchanged
;; Initial values of acc(umulator) and facts
[[] #{:a :b :d :e}]
{:m #{:e :k :d}, :c #{:b :a}, :f #{:e :c :d}}))
yes, that does it - interesting how you enclosed the initial accumulator and the facts
into an vector(for ease of destructuring, I guess?). I changed the initial acc to a #{} as a set is expected.
Just beware that maps aren't ordered. So you're not guaranteed to always get the same answer
ah, maybe I was to quick - it still doesn't re-attempt the evaluation as apparent by reordering values in dependencies
map:
(first ; At the end, get acc from the vector
(reduce (fn [[acc facts] [k v]] ; Each pass through, k and v will be a key and value from the map
(if (set/subset? v facts) ; If v is a subset of facts
[(conj acc k) (conj facts k)] ; Add k to both acc and facts
[acc facts])) ; Else pass them through unchanged
;; Initial values of acc(umulator) and facts
[[] #{:a :b :d :e}]
{:m #{:e :k :d}, :f #{:e :c :d}, :c #{:b :a} }))
;;=> [:c]
somehow I want to react to a state change in facts
and restart the reduce
operation once such change detected. Would it be 'atom' I'll need to use, or something to that effect?
Yeah, you could use an atom for that. There's a function add-watch
that you can use to set up a callback on an atom, to be run when the atom is changed.
@senya22: When iterating through dependencies, if the value is a subset of facts, you want that key to be added to facts. Also, keys can be added to facts by some other means. And every time facts has changed, you want to iterate through dependencies again, because there might be new values that are now subsets of facts. Am I understanding correctly?
yes, I want the reducing operation to react to the changes in the facts
state until all the elements in dependencies
map are exhausted, irrespective of the elements order there
@madstap: When you say: "Also, keys can be added to facts by some other means." - this is currently not required maybe in the future. Facts are given as an argument to the function and could be updated by it internally. Also retracting the facts from that set is not in scope so far, however making it reactive to any kind of change will be better than otherwise, I'd think
That's why I wasn't sure how to express something like that in idiomatic Clojure code
@seancorfield: Thanks for the link to java.jdbc documents.
@senya22: Does this satisfy the requirements? I wrapped the reduce in a loop recur to re-run if the facts were updated. Now the order of the hash is irrelevant.
(defn f [facts deps]
(loop [acc #{}
facts facts]
(let [[acc' facts'] (reduce (fn [[acc' facts'] [k v]]
(if (set/subset? v facts)
[(conj acc' k) (conj facts' k)]
[acc' facts']))
[acc facts]
deps)]
(if (= facts facts')
acc'
(recur acc' facts')))))
(f #{:a :b :d :e} {:m #{:e :k :d}, :f #{:e :c :d}, :c #{:b :a}})
(f #{:a :b :d :e} {:m #{:e :k :d}, :c #{:b :a} :f #{:e :c :d}})
Yes, that seems to be consistently returning #{:c :f} of 2 elements - you see any shortcomings with this approach?
@seancorfield: This page you recommended was helpful - I learnt that I can use :row-fn to read the clob returned from a query: http://clojure-doc.org/articles/ecosystem/java_jdbc/using_sql.html Here's how I did it:
(require '[clojure.java.jdbc :as j])
(defn clob-to-string [clob]
(with-open [rdr ( (.getCharacterStream clob))]
(apply str (line-seq rdr))))
(j/query db-spec ["select * from Report where refid = ?" "1"]
{:row-fn #(clob-to-string (:body %))})
@saicheong: Yes, that was the example I added to the gist that was posted earlier...
Bah, it imported the Gist, not the comments...
Anyways, hopefully that comment will show folks how to do it with the latest java.jdbc.
@seancorfield: I am using jdbc also. Not sure how to set up the db connection
(def mysql-db {:subprotocol "postgres" :subname :user :password })
Not sure what goes were as I have a db url and user and pass
does the url go in the subname?
Also getting this error when trying to insert:
java.lang.NullPointerException: null
(Unknown Source) java.lang.Class.forName0
Class.java:348 java.lang.Class.forName
RT.java:2087 clojure.lang.RT.loadClassForName
jdbc.clj:271 clojure.java.jdbc/get-connection
jdbc.clj:1098 clojure.java.jdbc/insert-rows!
jdbc.clj:1130 clojure.java.jdbc/insert!
(sql/insert! mysql-db :nlpanalytics
{:orgid "TEST"
:userid "123"
:incomingmessage "TEST INCOMING"
:conversationid "456"}
{:orgid "Rollio"
:userid "SSAM"
:incomingmessage "ROLLIO TEST"
:conversationid "456”})
Do many people use Spring Security for securing their API?
@josh_tackett: The simplest form is to use {:dbtype "postgres" :dbname "mydb" :user "myuser" :password "mysecret"}
That way you don’t have to worry about protocols and names etc.
I need to send a PR to http://clojure-doc.org to get that updated (and should probably update the README in the repo).
The error you’re getting is because the subprotocol
would need to be "postgresql"
for class-name (driver) auto-detection to work.
That aliasing should work by default (`:subprotocol "postgres"` should work) so that’s a bug. I never use PostgreSQL so support for it is based mostly on folks in the community providing feedback.
It is part of the core test suite locally, but that doesn’t extensively test db-spec
formats, just SQL / DDL operations on known, good database specs.
http://dev.clojure.org/jira/browse/JDBC-138 to address that.
http://dev.clojure.org/jira/browse/JDBC-139 to address documentation.
@seancorfield: but where do I put the database url?
{:dbtype "postgres" :dbname "mydb" :user "myuser" :password "mysecret”}
In this map there is no place to put my connection URL to actually write to the database
@josh_tackett: try adding a :host
entry -> https://github.com/clojure/java.jdbc/blob/f9fe3dde5b4bc5f1a5b5a79ffb5374fad3377b0b/src/main/clojure/clojure/java/jdbc.clj#L215
@josh_tackett: java.jdbc creates the URL for you.
If the host is not localhost, specify :host
(which can be a hostname or just an IP address). If the port number is not PostgresSQL’s standard, specify :port
.
The idea is that you specify the bare minimum you need.
Alternatively, you can specify the db spec as a string instead of a map — "
— or you can specify a map with just :connection-uri
that is that URI string.