Hello, why? I was expecting empty collection!
(valsย {}) => nil
the difference almost never comes up. from the vals
docs: "Returns a sequence of the map's values, in the same order as (seq map)." and (seq {})
is nil, so it seems to make sense.
some amount of related background can be found at https://clojure.org/reference/lazy
a common mistake when first coming to clojure is to focus too much on specific types whereas idiomatic clojure code tends to focus on interfaces.
for your example, (seq coll)
is used to check if a sequence has remaining items and (empty? coll)
is used to check if the sequence is empty. both of these idioms will work regardless of the underlying concrete type (eg. map, vector, list, nil)
I've got a http://java.io.File object and I want to get the path to the file. is it OK to just call str
on it ?
All I'm doing is using using me.raynes.fs to split out the filename from the parent folder name, I'm not actually doing any I/O so I think str will be fine. it seems more "string-manipulation-y"
seems fine. calling (.getPath f)
would also be reasonable
or depending on the use case, (.getCanonicalPath f)
or (.getAbsolutePath f)
good morning all
a nice easy question now for you :-) I want to extract a vector containing selected values from a map in a specified order e.g. (select-vals {:name "john" :age 37 :height 186} [:height :name])
==> [186 "john"]
.
I've come up with (defn select-vals [m ks] (reduce #(conj %1 (m %2)) [] ks))
which does the trick but experience has told me that every time I want to write a reduce
there's usually a built-in function I've missed
for me?? why ??
@tim.j.robinson you were correct there's a function called select-keys
that does that
Oh.. Not sure about the specified order.. You'd have to call vals after that
You could create a new one with (comp vals select-keys)
but it doesn't retain order..
((juxt :height :name) {:name "john" :age 37 :height 186})
perhaps
juxt takes fns as arguments, and returns a fn. When called it returns a vector whose first element is the result of calling the first fn and so on.
dang! I wouldn't have found that. yes that's it - thanks ๐
When I was starting with Clojure, juxt was one of those functions that blew my mind ๐ Actually, itโs pretty straightfowardโฆ just for clarity this would be equivalent to the example above:
((fn [m] [(:height m) (:name m)]) {:name "john" :age 37 :height 186})
This is exactly what juxt does in this case. Returns a function like: (fn [m] [(:height m) (:name m)])juxt
is the Spanish inquisition of Clojure
Hi, I want to write a method to convert key and value to keyword when I passing HashMap from Java, But it didn't work. The result like this: {a a}. My expect is like this: {:a :a}
(defn keywordize-kv [m]
(println (->> m
(into {})
(let [f (fn [[k v]] [(if (string? k) (keyword k) k) (if (string? v) (keyword v) v)])]
(walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))
))
)
@dstephensย Thank you. This is worked fine for me. But I am still wondering if I want to use ->> how should I return the value evaluated?
->> is a macro that puts the value of each consecutive form in the last position of the next (->> a b c)
is the same as (c (b a))
. Because of the let block, the meaning of your original code was something like
(let [] (walk (into {} m)) (into {} m))
The easiest way (imo) to use ->> on your code would be to move the let block up to the top level and thread inside it:
(defn keywordize-hashmap [m]
(let [keywordize-entry (fn [[k v]] [(if (string? k) (keyword k) k) (if (string? v) (keyword v) v)])
keywordize-map #(into {} (map keywordize-entry %))
keywordize (fn [x] (if (map? x) (keywordize-map x) x))]
(->> m
(into {})
(walk/postwalk keywordize))))
Now the macro will produce something like (walk keywordize (into {} m)
which is what you want!
Hope that helps.Thank you for your detailed explanation.
What does your input HashMap look like?
in the let block you don't use the threaded value at all, you use the original value of m
, the thread also means that you put m into the last position of the let block, i.e. the result of the walk is discarded and you just return the value you had before.
You had the right idea calling into {}
on m because otherwise it's not considered a map and walk won't attempt to traverse it.
(map? (HashMap.))
=> false
so maybe remove the thread at least until you have it working how you want:
(defn keywordize-kv [m]
(let [f (fn [[k v]] [(if (string? k) (keyword k) k) (if (string? v) (keyword v) v)])]
(walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x))
(into {} m))))
Hi! first time posting ๐ I have an issue with Calva where if I evaluate and pretty print a form and the output is several lines, I only see the first (I can see all lines in output.calva-repl). Is there a way to see all lines? I'm running in vscode on WSL2 @viebel
The inline display only shows the first line. You can peek definition to peek into the output/repl without opening it. Welcome to #calva !
avoid hiccup style formats as internal representations, they are nice for people to write, but because the structure is less regular they are annoying to write programs to manipulate
Let's say I have a map where the keys are Characters and the values are vectors or lists. Let's also say I have a list of tuples like (key_in_map, index_in_vector, value)
.
For each tuple I want to update the map by setting value provided in those "coordinates".
What would be the best way to do this other than mutating the map on each iteration (which I'm not sure is even possible)?
It is, and that is the way to do it, using reduce
If the values in the map are vectors it is a reduce using update-in, if they are lists or seqs it is pain
It is certainly possible to do it with reduce
and the most common way to do that in Clojure doesn't actually mutate the map -- it creates a new map in each step, each of which is nearly the same as the map created in the previous step.
There is a feature called transients that can be used that will actually create a mutable map, and mutate it in each step. That is an optional performance enhancement, and the code to do it looks almost the same as if you are using immutable maps.
can I use names from outer scope in binding forms? So that they are like closures
yes, the things we put binding forms into are things that create closures
(functions, let, binding, for, loop etc.)
Hi, I'm still new to Clojure and I want to transform a result set from:
[{:provider "A" :rate 10 :channel "C1"}
{:provider "A" :rate 10 :channel "C2"}
{:provider "A" :rate 10 :channel "C3"}
{:provider "B" :rate 20 :channel "C4"}
{:provider "B" :rate 20 :channel "C5"}
{:provider "B" :rate 20 :channel "C6"}]
To:
[{:provider "A" :rate 10 :channels [{:id "C1"} {:id "C2"} {:id "C3"}]}
{:provider "B" :rate 20 :channels [{:id "C4"} {:id "C5"} {:id "C6"}]}]
Since the query is a JOIN, provider
and rate
gets repeated on the result set. I want to group the channels
by those.
I've tried map, reduce, group-by, partition-by but I haven't gotten exactly to where I want yet.
Any pointers?@diego559 I'd start with (group-by :provider ...)
- that nearly fixes it, it's just a bit of massaging after that
nothing in core does it directly, but I think group-by is the shortest path
also, if provider / rate don't match, what happens then?
if they separate, you'd want (group-by (juxt :provider :rate) ...)
They always do because it's a JOIN, the come from the same record of the same table
OK
I think I did it. Does it look fine? Suggestions on how I can improve? Since I'm probably going to use this model in multiple other queries, I would like to get it right.
(->> (group-by :provider v)
(map (fn [e]
(let [[provider record] e
rate (:rate (first record))
channels (map :channel record)]
{:provider provider :rate rate :channels channels}))))
you aren't getting the :id
keys like in your example
and usually we'd use {:keys [rate]} (first record)
instead of rate (:rate (first record))
or even [{:keys [rate]}] record
but I feel like the implementation detail that the rate always matches the provider is being buried here - if you don't explicitly check, it should at least be documented
Thanks!
I used juxt
like you suggested to be more future proof. Now I need to figure out how to create a map with :id
for the channels.
(->> (group-by (juxt :provider :rate) v)
(map (fn [e]
(let [[[provider rate] record] e
channels (map :channel record)]
{:provider provider :rate rate :channels channels}))))
that should be straightforward with map (fn [x] {:id x})
or (partial hash-map :id)
or even #(hash-map :id %)
I was trying (map #({:id %})
but realized it doesn't work, don't really sure why it differs from (map (fn [x] {:id x}))
@diego559 reading without evaluating is informative - ' does that
user=> '#({:id %})
(fn* [p1__155#] ({:id p1__155#}))
if we rename the arg:
(fn* [x] ({:id x}))
Sorry, don't really understand what you mean. I thought #()
and (fn [])
where equivalent
it's a reader macro, using ' shows how it expands without evaluating it - notice how it adds parens around the body
fn has var-args for the body, so an implicit do
#() fills in the fn body as a template, and only uses one spot, so prevents using that implicit do
imagine if #(foo %)
expanded to (fn [x] foo x)
that would be following the same rule we'd need for #({:id %})
to become (fn [x] {:id x})
but it clearly isn't what you want
that's the best and most clear explanation i've seen for this
๐ป
Makes lots of sense, thanks!
hmm, can I rewrite this to more idomatic clojure
(defn convert-number-to-collection [number]
(->> number
str (map (comp read-string str))
read-string
is a big powerful thing, here it's probably better to use #(Long/parseLong %)
or just #(Long/parseLong (str %))
and skip the comp call
but then it would not change for example 12
into (1 2 )
what I need @noisesmith
how wouldn't it?
when I do
(defn convert-number-to-collection [number]
(->> number
str
Long/parseLong))
I get the output 12 instead of (1 2)
I never mentioned using it outside a lambda
it's a replacement for read-string, not the entire map call
sorry, then I misunderstood you
No matching method ParseLong found taking 1 args for class java.lang.Long
(cmd)user=> (defn convert-number-to-collection [number]
(->> number
str
(map #(Long/parseLong (str %)))))
#'user/convert-number-to-collection
(ins)user=> (convert-number-to-collection 12)
(1 2)
Alternatively, you could do something like this:
(->> 123 str (map #(Character/getNumericValue %)))
@roelof also consider this behavior of the read-string version:
)user=> (convert-number-to-collection "1.23")
(1 . 2 3)
@robert.mitchell36 that's a good one - btw map already calls seq
Good catch. I edited it out.
I am reading the Joy of Clojure and on the chapter about Macros, it says that if
is a macro but when I do in the repl (source if)
it says source not found
it's a special form, those are things implemented in the java code of the compiler
user=> (special-symbol? 'if)
true
conceptually it's like a macro (and might have even been one at some point?) - definitely not a macro today
oh, I see.
thanks
the way it's like a macro is that its body isn't pre-evaluated (even though it's the java code of the compiler managing what's done with the body, rather than a clojure function)
to see an example, maybe the source of and
would help (similar job to if, actually a macro)
or cond
I am trying to get a grasp of symbol resolution in clojure and have yet to understand behaviour of f
(as well as difference to behaviour of g
) below:
(def a 2)
(def b {3 3})
(defn f [x] (- a (first (map - [x]))))
(defn g [x] (b x))
((juxt f g) 3)
;; => [5 3]
(with-redefs [a 7, b {3 12}, - *] ((juxt f g) 3))
;; => [4 12]
It seems that the two occurences of -
inside f are resolved differently -- is that because in head position it is being compiled at definition time?
If so, what differentiates that +
inside f
from b
in g
? Both (ifn? +)
and (ifn? b)
are true for above values..+ and - have some special optimizations to try and make math fast
Functions themselves are immutable, but the Var that points to them isn't. Does that help to understand it?
When you redef, you're not changing the function, you're changing the function the Var reference points too
I was thinking more about "vars pointing from them" and what exactly should be considered the immutable value of a function -- as in difference between f
and v
here:
(def m {0 1})
(def f (fn [x] (m x)))
(def v [m])
((juxt f v) 0)
;; => [1 {0 1}]
(def m {0 2})
((juxt f v) 0)
;; => [2 {0 1}]
-- changing m
here does not change v
but changes result of evaluating f
.Currently my working model is "function has immutable structure, but everything in its closure is captured by reference", kind of like if we had something like [0 1 2 #always-deref (defn a (atom 4))]
to always deref its contents upon evaluation.
Oh I see what you mean. The difference is that Clojure auto-derefs things, but not inside fn
:
(def m {0 1})
(def f (fn [x] (m x)))
(def v [#'m]) ;; We tell Clojure not to dereference `m` automatically before creating the vector, by asking Clojure to pass us the Var and not the value the Var points too.
(def m {0 2})
(f 0)
;; => 2
@(v 0)
;; => {0 2}
And similarly, you can chose not to capture the Var in the closure, by forcing it to be dereferenced:
(def m {0 1})
(def f (let [m m] (fn [x] (m x)))) ; Since Clojure doesn't deref inside `fn`, we need to deref it outside, and close over the derefed value
(def v [m])
((juxt f v) 0)
;; => [1 {0 1}]
(def m {0 2})
((juxt f v) 0)
;; => [1 {0 1}]
So its not that everything in its closure is captured by reference
, everything is captured as-is. Its that Clojure has triple indirection. The symbol m
points to the Var #'m
which points to the value {0 1}
. So the function does not close over the symbol
, but it closes over the var that the symbol points too.
But when you do [m]
, Clojure will first resolve the value pointed by the symbol 'm
in the current namespace, which is the Var #'m
, and then it will do one more thing (which it doesn't do when inside fn
), it will also deref the Var, so it will get the value it points too which is {0 1}
and it will pass that to the constructor of vector, thus your vector contains: [{0 1}]
. Like I showed in my example, you can prevent this auto-deref of Vars by Clojure by telling it to give you the Var using (var m)
or #'m
.
Thanks for laying it out in detail! And to everyone in this thread -- it's been enlightening ๐
ah, I see, I'll try this out with different functions then
something to keep in mind is with-redefs is not really intended for us outside of things like stubbing/mocking in tests
for a function like (defn f [a] a)
you can imagine a call like (f 1)
gets compiled to something like (.invoke ^clojure.lang.IFn (deref (resolve 'f)) 1)
the var resolution doesn't actually happen everytime, it is resolved once when the class that the code is attached to, which makes things faster, and usually doesn't behave any different from the above.