This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-07
Channels
- # announcements (35)
- # beginners (80)
- # boot (1)
- # calva (4)
- # cider (33)
- # cljdoc (40)
- # clojars (3)
- # clojure (95)
- # clojure-berlin (2)
- # clojure-europe (4)
- # clojure-italy (28)
- # clojure-nl (2)
- # clojure-seattle (1)
- # clojure-serbia (1)
- # clojure-spec (74)
- # clojure-uk (71)
- # clojurescript (29)
- # core-async (1)
- # cursive (80)
- # data-science (4)
- # datomic (17)
- # duct (75)
- # emacs (4)
- # figwheel-main (5)
- # fulcro (3)
- # jackdaw (1)
- # java (1)
- # jobs-discuss (20)
- # off-topic (32)
- # parinfer (2)
- # pathom (23)
- # re-frame (26)
- # reagent (25)
- # rum (6)
- # shadow-cljs (122)
- # speculative (4)
- # sql (17)
- # testing (7)
- # yada (8)
Hello all, how do I handle with java.util.Collections
? Is there any way to convert it to Clojure collection?
If you have an arbitrarily nested java.util.Collections object, then you would need some kind of function that recursively 'walks' through it, converting each thing into a corresponding Clojure type. If you have a java.util.Set, and you know its elements are things like integers, strings, etc., then you should be able to simply call (set my-java-set)
, which will return a Clojure set.
I would bet that someone has written the recursive version of that for many kinds of java.util.Collections, but I don't know what library it might exist in.
If you know it contains String elements, then (set my-java-collection)
should do the job just fine.
unless you want a different kind of result, e.g. if you want a vector, then (vec my-java-collection)
You may want to assign the return value of that to a variable or let-bound symbol, and print out the value of (type val)
to see if it really is a Clojure vector, if you truly need an immutable Clojure vector, and not a Java mutable type. Java mutable types can be printed at a REPL in a way that looks the same as Clojure collections.
user=> (java.util.ArrayList. [1 2 3])
[1 2 3]
user=> (type (java.util.ArrayList. [1 2 3]))
java.util.ArrayList
java.util.Collections/list can convert the Enumeration type to a Java list, and from there you can call Clojure's set
or vec
on it to create an immutable value.
I was also just reminded while searching through the Clojure source code for "Enumeration" of the function enumeration-seq
, which takes a Java Enumeration, and returns a Clojure sequence.
Using that instead of java.util.Collections/list might be a little more efficient, since it might not allocate as much memory
Some code golf — is there something that can simplify this a little bit?
(let [results [{:_id 1} {:_id 2} {:_id 5}]
lookup {1 "a", 2 "b", 3 "c"}]
(map #(assoc % :val (get lookup (:_id %) "default")) results))
;; => ({:_id 1, :val "a"} {:_id 2, :val "b"} {:_id 5, :val "default"})
If you didn’t need a default you could have used
cljs.user=> (clojure.walk/postwalk-replace lookup results)
[{:_id "a"} {:_id "b"} {:_id 5}]
Oh wait you could not 😉
You also add :val
To me it looks perfectly idiomatic as is
Can also use for
:
(for [{:keys [_id] :as e} results
:let [val (get lookup _id "default")]]
(assoc e :val val))
;; => ({:_id 1, :val "a"} {:_id 2, :val "b"} {:_id 5, :val "default"})
I have posted the same question in the cljs channel, but am also posting here as the behavior is the same in clj.
I am exploring extend-via-metadata
and I am getting this behavior:
(defprotocol Component
:extend-via-metadata true
(start [component]))
(def component (with-meta {:name "db"} {`start (constantly "started")
`clojure.core.protocols/datafy (fn [x] (:name x))}))
(start component)
;; => started
(datafy component)
;; => db
(satisfies? clojure.core.protocols/Datafiable component)
;; => true
(satisfies? Component component)
;; => false
So when extending with datafy
protocol i get true when checking if the data satisfies?
the protocol.
However with a custom protocol with :extend-via-metadata true
I am getting false
in the satisfies?
check.
Is there something I am missing in the implementation?
thanks@fj.abanses satisfies?
doesn't work via metadata -- what you're seeing with (satisfies? clojure.core.protocols/Datafiable component)
is the implementation of that protocol for Object
, and component
is an instance of Object
.
Thanks @U04V70XH6, makes sense now.
It took me a bit of digging in the REPL to figure out what was going on!
is there a more idiomatic way to spread a map into map varargs? given (defn foo [a b & {:as x}])
(->> {:a 1} (apply concat) (apply foo 1 2))
is hideous
basically make a more graceful api? or is it a lot of functions so covering them doesn't really work?
yes, it's hideous, I think apply concat is nicer than interleave, and my solution is to never use & {}
(if I can help it)
also I think (apply foo 1 2 (apply concat x))
is nicer than the arrow form, but that's subjective of course
agree on the never use & {}
. I think interleave would be more meaningful to me when i see this in the wild 3 months after writing it. also agree don't thread but context of actual use dictates that ¯\(ツ)/¯
i just run into apis out of my control frequently enough to be irritated by it. wasnt sure if there was an applym
or something cute to be done with the core libs
no, there's nothing built in
@dpsutton perhaps as a compromise (def unwrap-map (partial apply concat))
ill import it right below leftpad 😉
@khardenstine quoting the bot on #clojure irc:
You have to do something like
(defn mapply [f & args] (apply f (apply concat (butlast args) (last args))))
, which just goes to show why unrolled keyword args are a bad idea
i just don't know what you gain either. I know common lisp used that style a lot but with map syntax so convenient it just seems worse in every regard
why (butlast args) (last args)
? What does that get you?
that's how the map gets flattened into a sequence. args = (a b {:x 3})
(concat (a b) {:x 3})
=> (a b :x 3)
yea i agree the syntax doesnt help enough, it just gets in the way of composition
to me it's intuitive that concat on a map would turn it into a list of keys followed by their values
incase anyone else code golfing wants a macro:
(defmacro applym [f & args] `(apply ~f ~@(butlast args) (apply concat ~(last args))))
presumably
this doesn't work if the map isn't a literal, and a big reason to want something like applym is to reuse a default map for the args
that would preserve a symbol
(macroexpand '(applym foo 1 2 k))
=> (clojure.core/apply foo 1 2 (clojure.core/apply clojure.core/concat k))
I use kwargs and & {} all the time, yet never have this issue. can someone back up and tell me a real scenario where you’re doing this?
presumably programatically creating the args and then having to use a function that uses & {}
I guess I tend to use them on the outer layer where it’s people, not programs
yea specifically im progmatically calling into an api with kwargs
and you prefer (invoke :arg1 :a :arg2 :b)
instead of (invoke {:arg1 :a :arg2 :b})
for humans?
we’ve actually contemplated a small change that would make either automatically work in Clojure
if you use & {} in the args
that would be cool
it doesn’t invalidate any existing code, just a tweak in destructuring
well, maybe it’s in the compiler, I don’t remember
possibly 1.11 feature :) but don’t quote me on it
(defn a [b & [{:keys [c d]}]])
would be unaffected I guess
correct, effect is allowing something new in the invocation
Anyone have any recommendations: I'd love something to "organize" my requires and imports. Remove unused, and alphabetize would be nice
I use Cursive, but I don't think it does this
I installed a plugin for line sorting and ended up putting a newline between (:require
and the first actual require
needless to say, that makes that I now have about three different ways of requiring things
Interesting. What's the plugin?
I recall that there is also a leiningen plugin that can complain/fix requires
but its name left me
I think eastwood will do the job at complaining at me, but doesn't fix
yeah there is a fixing tool, but remembering names is really challenging
That's a great name, haha
such a googleable name that I ended up searching for my coworkers slack message :’)
Ha, yes too generic
thanks
There are some issues with slamhound and Clojure v 1.10 fwiw
Is there a way to define in the environment where deps.edn is located? Using nextflow and the workaround I'm using is to cp deps.edn to current directory, but it's messy/lazy.
no, not currently