This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-11
Channels
- # beginners (104)
- # boot (14)
- # cider (10)
- # clojure (38)
- # clojure-australia (3)
- # clojure-dev (11)
- # clojure-spec (8)
- # clojurebridge (2)
- # clojurescript (50)
- # core-async (118)
- # emacs (3)
- # expound (2)
- # fulcro (39)
- # jobs (3)
- # jobs-discuss (17)
- # kaocha (2)
- # lumo (1)
- # off-topic (16)
- # onyx (1)
- # re-frame (1)
- # reitit (24)
- # shadow-cljs (14)
- # sydney (1)
- # tools-deps (14)
- # yada (1)
You can use reduce
as demonstrated by didibus, but in my head what you want is to take the values of d
, filter them by the key "capex"
take the key "hours"
from each and sum them up. This, in Clojure, encodes to
(->> d
vals
(filter #(true? (get % "capex")))
(map #(get % "hours"))
(apply +))
If your keys were keywords like so:
(def d {
"project A" {:hours 7, :capex true},
"project B" {:hours 3, :capex false},
"project C" {:hours 6, :capex true}
})
you could have used the keywords as functions themselves
(->> d
vals
(filter :capex)
(map :hours)
(apply +))
Looks like a question I was asked during a whiteboard exercise. Big thing I took away from it is that the threading macro makes whiteboard programming easier.
Anytime you need to loop over a collection and get a reduced value out of it. Like a sum, average, etc. You're looking for reduce
Going through the examples at: http://www.4clojure.com/problems is a good way to get better at processing data with Clojure. If you struggle too much on one of the problem, you can look at the solutions of others.
As a general quick intro guide to learn the language, I always recommend: https://aphyr.com/posts/301-clojure-from-the-ground-up-welcome
And you'll be surprised how much you learn by reading over every section in the official reference: https://clojure.org/reference/reader
As well as the official guides: https://clojure.org/guides/getting_started
can you guys please help me understand why (into nil [56]) results in (56) and (into (into nil [56]) [89]) results in (89 56) but (into (89) [56]) results in ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/eval1168 (form-init1780124488703515866.clj:236) thank you in advance for help you can share
Watch this one when you have time: https://www.youtube.com/watch?v=P76Vbsk_3J0
@mcferren Yes, its because (89)
is not how you define a literal list. You must type it like so: '(89)
.
@mcferren There is also (list 89)
which is possible.
(89)
is evaluated as a function call where the function is 89 - numbers are not coercible to a function (i.e. something which implements the java IFn
interface), so you get an error.
@U8MJBRSR5 and (into nil [56]) returns a literal list? Thanks Vincent
I thought it has to do with "casting" a vector into a list but i was actually trying to "cast" a vector into a function call
Read my replies in the main chat room after your question if you want to understand the details.
The short answer is (into nil [56]) returns a list data structure. When typing out Clojure code lists literals must be quoted '(89)
or (quote 89)
. But in EDN they don't have to be.
That's because Clojure code is read and evaluated (unless quoted). And EDN is only read, it is not evaluated.
Where literal means textual representation. And data structure means internal binary representation.
thanks @U0K064KQV My main intent was to understand how default value was handled when calling a reduce function that mutates upon this key during each iteration
Haha, ya. You got down a bit of a rabbit whole here. Since your issue had nothing to do with that really.
If you type it without the quote, the reader reads it as an S-expression, and Clojure will try to call the symbol 89 as if it were a function. But 89 is not a function (IFn), it is a Long. Thus you see the exception.
First, the text that you typed (your code), goes through a "read" phase. Basically, the text is parsed into a data-structure. In that phase, (89)
becomes a List, and [89]
would become a vector. But, the second phase will take the read data-structure and evaluate it as Clojure code.
And in this evaluation process, all List are treated like syntax for function execution.
So "(89)"
is read into (89)
which is then evaluated such that 89
is called as if it were a function with no arguments. That's when you see the exception.
That's done using the quote
special form. Which '
is a syntax sugar for. Thus "'(89)" becomes (quote (89))
which is evaluated into (89)
. The quote tells Clojure, don't evaluate what comes next, just return it as it was read.
And this is the underlying principle for homoiconicity. Clojure code is actually a data-structure. When you evaluate Clojure code, you just perform a walk on the data-structure, and based on the type of the elements and their position, you perform various actions.
And this data-structure has a literal text representation. The reader is used to parse your text into that data-structure.
Now there's actually a third phase. The macro-expansion phase. That phase happens after the text was read into a data-structure, but before the data-structure gets evaluated. In that phase, you are given a chance to modify the data-structure that was read, before it gets evaluated. That is what the macros do.
But, this is probably a rabbit whole of info given the question you asked. So don't worry if it doesn't all make sense to you quite yet. It will one day. 😛
First time I got a problem with Java interop 😛
(ns some-ns.core
(:import
[java.util UUID Locale]
[com.devskiller.jfairy Fairy]))
(def ^Fairy fairy (Fairy/create (Locale/getDefault)))
(.person fairy)
I’m trying to use this one https://github.com/Devskiller/jfairy
The error is IllegalArgumentException No matching field found: person for class com.devskiller.jfairy.Fairy clojure.lang.Reflector.getInstanceField (Reflector.java:271)
Which is quite funny because I can see in source code that the property exists in Fairy class.
Can someone please help me?@kwcharllie379 It looks like the person method takes a varargs argument. I think this means you'll need to invoke it with an empty array to achieve the same as the docs from clojure. This stackoverflow post is for a similar problem: https://stackoverflow.com/questions/48138406/calling-java-function-with-optional-parameters-from-clojure
@toby924 But how can I get the inner class of PersonProperties?
PersonProperties.PersonProperty
would become PersonProperties$PersonProperty
. More examples here: https://stackoverflow.com/questions/7140843/how-to-access-static-inner-java-class-via-clojure-interop
This is to do with how Java creates inner classes at compile time rather than a Clojure specific thing
(println (PersonProperties$PersonProperty))
Throws an error CompilerException java.lang.RuntimeException: Unable to resolve symbol: PersonProperties$PersonProperty in this context, compiling:(/Users/karol/Workspace/clojure/zbd-faker/src/zbd_faker/faker.clj:13:10)
Ok got this
Thank you very much Toby 🙂
Missing import?
No problem 🙂
yes 😛
I have a data structure like this:
(def data
[[:id [[1 374] [2 375]]]
[:name [["str-1" "str-2"] ["str-3" "str-4"]]]])
I would like to turn it into this:
[ [1 374 "str-1" "str-2"] [2 375 "str-3" "str-4"] ]
data
can have any number of key + coll
tuples in it. Most of my solutions end up being overly verbose so I wanted to get others takes on this.@tkjone apply map concat - never mind, that's not quite right
user=> (apply map concat (map second data))
((1 374 "str-1" "str-2") (2 375 "str-3" "str-4"))
and if you can guarantee the input are always vectors
Why do we have to use apply for first map?
Compare with this, which is what happens in the end
(map concat
[[1 374] [2 375]]
[["str-1" "str-2"] ["str-3" "str-4"]])
So, concat would be mapped onto both collections. Right.
Much cleaner than what I had. Thanks for the input!
Hmm, I expected (vec ...)
to be implemented in terms as (into [] ...)
or the other way around, but thats not the case. Are there situations where I would want to prefer one over the other?
Prefer into
if the source is not effectively immutable. For example, trouble:
cljs.user=> (def x #js [1 2 3])
#'cljs.user/x
cljs.user=> (def y (vec x))
#'cljs.user/y
cljs.user=> (aset x 1 :no)
:no
cljs.user=> y
[1 :no 3]
That is only a concern on the non JVM based implementation then?
It can cause a problem on the JVM as well:
user=> (def x (into-array [1 2 3]))
#'user/x
user=> (def y (vec x))
#'user/y
user=> (aset x 1 17)
17
user=> y
[1 17 3]
right, so vec
is better if I can assume that the to-be-transformed collection is immutable
This will soon be true on both Clojure and ClojureScript, for example
(let [v [1 2 3]] (identical? v (vec v)))
Yeah, I would like to say vec
is always better, unless you are giving it data that can be changed underneath it
Cool! I saw that kibit was suggesting it, and I discussed with a coworker
unless you give it macro’s 😉
It suggests reducing (reduce #(and %1 %2) true coll)
to (reduce and true coll)
, but thats wrong
But it gives solid tips otherwise, its great when you are starting out (like I am)
Yeah, it is, it just fails to realise that and
and or
are macros instead of functions
You could file an issue with some code that demonstrates the problem on the Kibit project on Github, in case someone figures out a way to improve on that behavior. Looks like Kibit is still being updated.
Tools like Kibit and Eastwood are I expect fundamentally going to give wrong messages in some cases, but certainly nice if those can be reduced.
I think there already is a tracking issue: https://github.com/jonase/kibit/issues/142
Otherwise I obviously would, its the easiest way to contribute right 🙂.
in general, how much more expensive if fooAA than fooBB in my example? Thank you in advance for your insight.
I wouldn't worry about it, unless you're trying to do some kind of massive data transform.
I have come across this often so I am trying to get to the bottom of what is the correct general practice. For me it seems fooBB is quicker because it keeps the same object in tact but fooAA has been more legible is certain situations. I just don't know how expensive it may be to add a new container obj with a references to the contents of the original obj (which I think is what is happening to whats returned from fooAA)
even if it is a massive data transform, isn't this a simple matter of creating small "pointer references" ?
Here's a thorough benchmark about many ways to do it: https://gist.github.com/nathanmarz/bf571c9ed86bfad09816e17b9b6e59e3
I think, but I'm not sure. The difference is that update uses the same persistent data structure, and modifies it. Where as in fooAA, you create a new one. Don't know how that really reflects on performance
This is the code for the benchmark: https://github.com/nathanmarz/specter/blob/4778500e0370fb211f47ebf4d69ca64366117b6c/scripts/benchmarks.clj#L87
It seems using reduce-kv
might be best in terms of performance and using something built in.
@mcferren If this was too complicated. Here's what I would recommend you do. Add a function in your code like this:
(defn map-vals
"Map f over every value of m.
Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
f is a function of one arg, which will be called which each value of m, and should return the new value."
[f m]
(reduce-kv (fn [m k v]
(assoc m k (f v)))
{} m))
@mcferren And if you're looking to update specific keys only, I would use assoc or update. But if you are looking to update all keys, I would use map-vals
.
@mcferren And if you want to update specific keys only, and also get a map with only those keys that you updated, you can combine map-vals
with select-keys
like so:
user>(map-vals inc (select-keys dab [:bbb :ccc]))
=> {:bbb 1, :ccc 1}
@mcferren And finally 😝 , if you're going to be updating a lot of nested data-structures, I would use the Specter library: https://github.com/nathanmarz/specter