This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-16
Channels
- # announcements (33)
- # asami (37)
- # autochrome-github (1)
- # aws (5)
- # babashka (26)
- # babashka-sci-dev (18)
- # beginners (63)
- # biff (1)
- # calva (66)
- # cider (15)
- # clj-kondo (24)
- # cljs-dev (2)
- # cljsrn (14)
- # clojure (62)
- # clojure-doc (1)
- # clojure-europe (15)
- # clojure-nl (11)
- # clojure-spec (12)
- # clojure-uk (4)
- # clojurescript (45)
- # community-development (2)
- # cursive (34)
- # datahike (7)
- # datomic (7)
- # events (1)
- # figwheel-main (5)
- # fulcro (19)
- # gratitude (7)
- # holy-lambda (85)
- # hyperfiddle (4)
- # jobs (7)
- # jobs-discuss (25)
- # kaocha (4)
- # lsp (11)
- # off-topic (1)
- # polylith (20)
- # portal (14)
- # practicalli (6)
- # proletarian (5)
- # rdf (52)
- # re-frame (13)
- # reagent (48)
- # releases (1)
- # remote-jobs (3)
- # shadow-cljs (7)
- # tools-deps (17)
I have a map data, how can I get all of the value with id.
(def group-m {["Project.5655"
"Project-name"
"address"
"jack"
"139543188333"]
[{:id 429520,
:identifier "Project.5655",
:project_name "Project-name",
:task_name "address",
:user_name "jack",
:phone "139543188333",
:vars
"{\"max\": true, \"width\": 1594, \"height\": 830, \"isChange\": false, \"isChuShe\": false, \"auxiliary\": null, \"isChongShen\": false, \"isImportant\": false, \"socialLowInvest\": false}"}
{:id 429525,
:identifier "Project.5655",
:project_name "Project-name",
:task_name "address",
:user_name "jack",
:phone "139543188333",
:vars
"{\"max\": true, \"width\": 1594, \"height\": 830, \"isChange\": false, \"isChuShe\": false, \"auxilia
ry\": null, \"isChongShen\": false, \"isImportant\": false, \"socialLowInvest\": false}"}]})
or how can I translate this data struct to below struct
{["Project.5655"
"Project-name"
"address"
"jack"
"139543188333"] [429520,429525]}
@imxingquan Took me a while to understand what you're asking. As before, it would really help if you explained/showed what you have tried so we can guide you along -- otherwise it feels like we're just doing your homework.
So you have a vector of hash maps (as the value in the group-m
hash map). You want to get the value of the :id
in each hash map. If you had just this hash map, how would you get the value of the :id
key?
{:id 429520,
:identifier "Project.5655",
:project_name "Project-name",
:task_name "address",
:user_name "jack",
:phone "139543188333",
:vars
"{\"max\": true, \"width\": 1594, \"height\": 830, \"isChange\": false, \"isChuShe\": false, \"auxiliary\": null, \"isChongShen\": false, \"isImportant\": false, \"socialLowInvest\": false}"}
(how do you get the value of any specific key in any hash map?)Then, since you have a vector of items (hash maps) and you want to apply that same operation to each item in the vector, how would you do that?
At that point, you should have code that can be applied to values in your group-m
hash map to produce the values you want, so then you need to walk a hash map, producing a new hash map with the same keys as the original but with your code applied to the values.
If you're using Clojure 1.11, you could use update-keys
for that. Otherwise you probably want reduce-kv
:
(reduce-kv (fn [m k v] (assoc m k (my-fn v)) {} group-m)
where my-fn
is the code above to apply the element selector to each item in the vector v
.Does that make sense @imxingquan?
The key is always breaking down the problem into smaller pieces that you already know how to solve.
thanks @seancorfield . Next time, I will try to make changes according to what you said. I am sorry that SOMETIMES I do not know how to express in English. Now I still need to use translation tools
Don't worry about your English, but show the code you've tried, and try to reduce the problem to simpler data structures that make it clear what you're trying to do. For example, if you started with {:a [{:id 1 :b 2} {:id 3 :c 4}]}
and said you wanted {:a [1 3]}
, that would have made it easier for folks to understand the problem, instead of trying to figure out what parts of the larger data structure are relevant.
Had you tried map
or reduce
on this already?
I tried do
(def m {:a [{:id 1 :b 2} {:id 3 :c 4}]})
{:a (vec (map #(:id %) (first (vals m))))}
;; => {:a [1 3]}
It turns out to be correct but I don't think I understand it very wellThat works only because your initial hash map has only one key/value pair. Maps are inherently unordered so you can't guarantee what order keys
or vals
produces (although they will be consistent with each other):
dev=> (def m {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9})
#'dev/m
dev=> (vals m)
(5 7 3 8 2 4 6 9 1)
dev=> (keys m)
(:e :g :c :h :b :d :f :i :a)
dev=>
Instead of (vec (map ...))
you could use (mapv ...)
which will also avoid creating and then realizing a lazy sequence.
Instead of #(:id %)
you could use :id
-- keywords can be treated as functions when applied to hash maps and they look themselves up in the map.
If you know your starting map has only one key/value pair, you might consider:
dev=> (def m {:a [{:id 1 :b 2} {:id 3 :c 4}]})
#'dev/m
dev=> (let [[k v] (first m)]
#_=> {k (mapv :id v)})
{:a [1 3]}
dev=>
(first m)
produces a key/value pair and [k v]
destructures that so k
is bound to the key and v
to the value.(it's late here so I'm off for the night -- good luck and I expect others will be around to help long before I'm back at my computer!)
Thank you very much @seancorfield I got it . you explain very clean. I am very benefit. have a nice day. see you tomorrow!
Hi!
I have a list of '(fn arg1 arg2..)
, what is the "right" way to execute them? Just eval
? Can I do this pattern in a more idiomatic way, or am I overthinking it?
(defn run [fns cols keys]
(->>
(map list fns cols keys)
(map eval)))
(run '(get get) '("abcdef" "ABCDEF") '(2 3))
=> (\c \D)
Don't use a quoted list but a vector containing the functions. Then you can apply them directly
Elaborating on what @U06BE1L6T explained:
(run '(get get) '("abcdef" "ABCDEF") '(2 3))
Here you actually donāt pass the function get
in, but the symbol. This will be resolved in run
by eval
, but in theory this could resolve to a different function!
E.g., when calling run
from a different namespace that has (defn get)
in it.
Easier, if you can:
(defn run [fns cols keys]
(map (fn [f c k] (f c k)) fns cols keys))
(run [get get] ["abcdef" "ABCDEF"] [2 3])
Also using map
may not fully realise the sequence of fn's unless the resulting sequence of results is fully realised.
Use mapv
or rewrite to use a reduce
(or use run!
if you are simply executing the fn's for their side effects and don't care about the results)
thanks a lot!
@UBU374R1P & @U06BE1L6T - I do not understand how vector is better than list tho, how come it does not suffer the same issue
anyway, so I suppose that using backtik (to get fully qual name) is better than the list quote, right?
the usecase is that the functions are "getters", and I construct the list based on other data; basically, cols are data, fns are program (constructed on the data) and the keys are state, that changes (e.g. what element do I get
; not sure this helps tho
The difference is qouting not the list data structure itself - try (list get get) Vectors are just convenient and prevalent in Clojure code I do not quite understand your use case but it seems to me that you are making it more complicated than necessary
Ok, thx everyone!
Iām a bit of a noob with both spec and schema (Iāve mostly just picked them up by reading examples in code, so my mental model might be off). Is there a way in either or both of spec/schema (preferably both) to model data that can look like either of these:
{1 {:c :d}}
{1 {:a {:c :d}}}
{1 {:a {:c :d}
:b {:e :f}}}
i.e. the key 1
can have {:c :d}
as a direct child, or it can have an intermediate child :a
which then has {:c :d}
as its child, and it can also have an intermediate child :b
with separate data associated with it. (the actual use case is a more complex structure but this is the core issue Iām hung up on)Are these valid maps?
{1 {:a {:c :d}
:c {:g :h}}}
{1 {:a {:c :d}
:b {:e :f}
:c {:g :h}}}
If not and you have a lot of restrictions like that, spec might not be the right tool for you because maps are open in spec: if a map has more keys than spec knows about, it won't complain by default. You can make it more strict but it kind of goes against spec's principle.
No idea about schema, never used itI think itās OK if those are valid
Basically my scenario is that currently, this data can only have the {1 {:c :d}}
form, and spec & schema are both used in the codebase to validate this (spec and schema are used separately in different places; yes, itās a bit redundant)
Iām trying to migrate this structure eventually to {1 {:a {:c :d}}
so that there can be an optional :b
key with different data under it. However in the intermediate state, I need to support both the nested and non-nested form, and Iām not sure how to change the spec/schema validators appropriately
But maybe the easiest solution is to temporarily disable or relax the validation during this intermediate phase
If you're using s/keys and :req now, https://clojuredocs.org/clojure.spec.alpha/keys > The :req key vector supports 'and' and 'or' for key groups: > (s/keys :req [::x ::y (or ::secret (and ::user ::pwd))] :opt [::z])
It's optional for single-argument functions in .
and ->
forms (and a few other threading-like constructs).
I prefer it when using ->
to draw a distinction between key selection (which I don't wrap in parens) and function calls (which I do) -- so all functions, whether single-argument or multiple arguments, have (
)
around them. But I think I'm kind of unusual.
dev=> (let [x [42]] (if (nil? x) "" (. x (toString))))
"[42]"
dev=> (let [x [42]] (if (nil? x) "" (. x toString)))
"[42]"
dev=> (let [x [42]] (if (nil? x) "" (.toString x)))
"[42]"
i donāt make the key selection v function call distinction, but i agree with the āalways have ()
in threadsā idea
@jjaws (-> some-map :foo (even?))
for example
I often use ->
when navigating into a nested map and maybe applying a function or two: (some-> req :params :id (parse-long))
is an example from our work codebase.
Sorry to barge in mid - conversation, please reply when u get the chance
I am trying to check if a string starts with double double quotes (for example, ""test"") using the starts-with?
function, although to no avail (tried using escape characters and such, but it didn't go well too)
Any ideas or other functions I can explore? (I can always resort to regex)
905 user> (str/starts-with? "\"\"test\"\"" "\"\"")
906 true
907 user>
starts-with?
works for me.
whenever you have double-quotes in a string each "
needs to be quoted
Ohh so I was definitely missing that Thank you so much for the fast reply, much appreciated! @U02EA2T7FEH
my pleasure
sorry to barge in with a meta point, but always type out what you did try specifically
simply copying REPL input/output is usually sufficient (with a description of what you're trying to achieve, which you did say š )
Hi there, folks. Iām having a hard time running tests usingĀ `with-redefs`Ā onĀ `char-array`Ā in one of my tests. testing.clj -
(ns testing.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
(defn step1 [stuff]
(conj [] stuff))
(defn testing-templates [stuff]
(-> stuff
step1
char-array))
testing-test.clj
(ns testing.core-test
(:require [clojure.test :refer :all]
[testing.core :refer :all]))
(defn fake-step1 [arg]
(conj '() (keyword arg)))
(defn fake-char-array [arg]
(conj arg :char-array))
(deftest testing-templates-test
(with-redefs [step1 fake-step1
char-array fake-char-array]
(is (= '(:abc) (testing-templates "abc"))
)))
And here are the results:
(run-tests)
Testing testing.core-test
ERROR in (testing-templates-test) (Numbers.java:1368)
expected: (= (quote (:abc)) (testing-templates "abc"))
actual: java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.lang.Character {... ...}
Is it not allowed to use with-redefs
on char-array
? It could be something dumb on my part, but I hope not! šchar-array is part of clojure.core, which is compiled with AOT direct linking, so calls within the already compiled clojure core to char-array will not be affected by with-redefs
Gotcha.
I'm not sure that's the issue here. it might depend on the order of compilation and options here
and char-array has an inline arity (sort of like a macro version of the function) attached as metadata, so the compiler will prefer to use that when not used as a higher order function
oh right, I forgot that one was an inline
Thanks, guys.