This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-04-18
Channels
- # announcements (1)
- # babashka (16)
- # beginners (39)
- # calva (17)
- # cider (21)
- # cljs-dev (1)
- # clojars (2)
- # clojure (39)
- # clojure-australia (1)
- # clojure-europe (1)
- # clojure-spec (7)
- # conjure (1)
- # cursive (6)
- # datomic (2)
- # depstar (5)
- # graalvm (20)
- # instaparse (11)
- # meander (4)
- # pathom (4)
- # pedestal (3)
- # polylith (18)
- # re-frame (13)
- # reagent (4)
- # reitit (3)
- # shadow-cljs (2)
- # spacemacs (14)
- # vrac (1)
I have a vector of hash-maps (def my-data [{:id "1" :value "a"} {:id "2" :value "b"}])
. Now I want to lookup an :id
and change the respective :value
.
This does not work:
(map (fn[x] (if (= :id "1")
(update x :value "c")
x))
my-data)
Ok, now I have
(map (fn[x] (if (= (:id x) "1")
(assoc x :value "c")
x))
my-data)
which works fine, but is this how you would do it or is there a more concise way?
I think that looks pretty good, you can look at destructuring map arguments and the for
macro to make it more concise
You can also write #( %)
instead of (fn [x] x)
(map #(if (= "1" (:id %)) (assoc % :value "c")) le-data)
an "anonymous function"
An alternative is to structure your data differently, instead of having a vector of maps (entities), you can have a map from ids to entities, which makes it more convenient to update a specific entity by id. Something like:
(def indexed-data
{"1" {:id "1", :value "a"}
"2" {:id "2", :value "b"}})
(assoc-in indexed-data ["1" :value] "c")
The medley library has a function medley/indexed-by
that does this transformation, or you can write your own:
(defn index-by [f coll]
(into {} (map (juxt f identity) coll)))
(= indexed-data (index-by :id my-data)) ;=> true
If you need to keep the order it gets a little more complex, but you could add an :order key to the entity.https://github.com/redplanetlabs/specter is really good at all these mutations
Thanks @U1Z392WMQ but my goal is to understand the basic functions on seqs better - especially for nested structures this is still brainteasing. 😉
I second the idiomatic
{"key1" {:name "jax"}
"key2" {:name "jin"}
"key3" {:name "jan"}}
style, because it's super easy to assoc new maps by giving them an unique key, and easy to update-in, assoc-in, and get-indissoc "key1" also removes the whole entry, quite handy.
Ok, now I have
(map (fn[x] (if (= (:id x) "1")
(assoc x :value "c")
x))
my-data)
which works fine, but is this how you would do it or is there a more concise way?
if i'm running something in a doseq
with a (Thread/sleep ...)
between loops, how do I ctrl-c or otherwise interrupt the loop?
Editors like Emacs/Cider has direct support for Ctrl-C. Or maybe you can just wrap it with future and use future-cancel
Ctrl-C does not interrupt the loop for you when you run lein repl
? What OS are you using, and what is the output of lein version
? Ctrl-C interrupts evaluation for me with macOS 10.14.x and lein version
2.9.5
An alternative is to structure your data differently, instead of having a vector of maps (entities), you can have a map from ids to entities, which makes it more convenient to update a specific entity by id. Something like:
(def indexed-data
{"1" {:id "1", :value "a"}
"2" {:id "2", :value "b"}})
(assoc-in indexed-data ["1" :value] "c")
The medley library has a function medley/indexed-by
that does this transformation, or you can write your own:
(defn index-by [f coll]
(into {} (map (juxt f identity) coll)))
(= indexed-data (index-by :id my-data)) ;=> true
If you need to keep the order it gets a little more complex, but you could add an :order key to the entity.I want to write out (and read) a nested data structure. Basically the EDN format would be perfect, only prn-str
writes everything in one line. Is there a way to get a more readable structure (eg. like Firefox does with JSON raw data)?
https://www.clojure-toolbox.com/ also shows: https://github.com/brandonbloom/fipp https://github.com/AvisoNovate/pretty If you need other options.
I tried pprint but it somehow did not work because the outermost structure was a vector. After changing this to a hashmap (what I wanted to do anyway) now it really looks pretty. 😉
@U7D5724A2 if you're printing large datastructures, you should be aware of clojure.core/*print-length*
and clojure.core/*print-level*
- if those dynamic vars are bound, you may be surprised when pprint prints something that you can't read back in 🙂
and if you're doing this a lot, fipp
is nice and faster than pprint; in fact, it's useful to even set it as the default pretty printer in your CIDER repl, etc.
i want to output nested html for a nested structure.
good time to use clojure.walk?
Sounds more like an application of Hiccup.
Here's an example input and desired output to get more concrete.
;jars-and-lids-to-html
(def datar [{:jar "hax" :lid "##"} {:jar "snax" :lid "##"} {:jar "slax" :lid "##"}])
desired output:
<html>
<span class='jar'>hax <span class='lid'>##</span> </span>
<span class='jar'>snax <span class='lid'>##</span> </span>
<span class='jar'>slax <span class='lid'>##</span> </span>
</html>
That looks quite achievable with Hiccup, just map over the collection with hiccup vectors for each element. You can use eg. [:span.jar ...]
shorthand for classes
Brilliant. Thank you! 😃
kinda like (map (html [:span.jar (:jar %)]) datar)
?
You generally want just one invocation of the html
macro at the top level, so something like
(html [:html (for [{:keys [jar lid]} datar] ...)])
Hmm.. I don't exactly get it but I'll play around with it
(hiccup.core/html
[:html
(for [{:keys [jar lid]} datar]
[:span.jar jar
[:span.lid lid]])])
;; => "<html><span class=\"jar\">hax<span class=\"lid\">##</span></span><span class=\"jar\">snax<span class=\"lid\">##</span></span><span class=\"jar\">slax<span class=\"lid\">##</span></span></html>"
Amazing. Thank you!