Fork me on GitHub
Itay Dreyfus09:09:54

Is there a nice way to map collections that will return a flattened one? So (map vector [1 2 3] [4 5 6]) → [1 4 2 5 3 6]

Ben Sless09:09:11

have you looked at mapcat?

Itay Dreyfus09:09:37

That's better. Thanks! 🙂

Ben Sless09:09:15

This also looks like interleave

Ben Sless09:09:55

(in your specific use case)

Ben Sless09:09:23

but a more general note, you almost never need flatten. I still haven't found one case where it's the appropriate solution, so if you happen to reach for it or something similar, it's almost a hint there's a better more specific solution

Itay Dreyfus09:09:58

Good point, thanks!


hi guys, is there maybe a function that trims character from string but not blank space


some arbitrary character, or characters?


if someone worked in php, there is such function which by default trims blank space, but you pass arbitrary characters as well

Martin Půda13:09:16


[org.apache.commons/commons-lang3 "3.12.0"]
(StringUtils/strip "a foo a" "a")
=> " foo "

Ferdinand Beyer13:09:41

You could just use clojure.string/replace with a regular expression:

(str/replace "a foo a" #"^[a]|[a]$" "")


thank you both for suggestions


You can make your own, using @U922FGW59's suggestion.

(defn trim 
  ([string] (trim "\\s" string))
  ([char string]
  (str/replace string 
               (re-pattern (str "^[" char "]*|[" char "]*$"))

(trim (trim "a" "aaa foo   a")) ;; => "foo"

✔️ 1
Jo Øivind Gjernes17:09:17

Is there any json library that keeps ordering ? i.e. enforces array-map?


I do not know, but a nitpick: if it did use array-map to preserve ordering of the input key/value pairs, then if in memory you did an assoc on one of those array-map instances, and it had over 8 keys in it, it is nearly certain that it will return a hash-map, with the key/value ordering lost.


If you want something that reads json, and then lets you change the data, and spit out json at the end, I would think you would want something that used a data type other than Clojure's built-in array-map. Either that, or you would need to be very strict in how you updated such array-map's if you wanted order to be preserved, e.g. create brand new array-maps from the existing ones, with different key/value pairs.


If there were a json library that used this ordered-map data structure in this library, that would make it easier to update ordered-maps without losing the input order: I do not know if such a json library exists.


maps don't have order


full stop. it is not intentional that clojure's array-map preserves order


There are places in Clojure's implementation (a very very few) where the fact that array-map preserves order is used explicitly.


@US3NQ875H what sort of situation are you in where you need map ordering?


this is a bit common on the frontend, libs are written that consume maps where the order of the keys is important

👍 1

i have had to patch some libs i use to consume arrays as well...


i think in cheshire you can have an encoder for a type you make that in clojure looks like a list of mapentries, and cheshire would render that as a json map, preserving your order

Jo Øivind Gjernes18:09:00

Some non-clojure language generates a query result returned in a certain order, making it non trivial to figure out the expect order. Passing through the clojure backend it looks like we’re shuffling results once they contain more than 8 columns 😂


clojure does array->hash-map promotion after your persistent map gets to be ~8-10 items big. if you are consuming a json map you could write a decoder that returns vectors of mapEntries, thus preserving order and you can write protocol functions to make it a proper type that acts exactly like a persistent map. or tell the producer to stop screwing around and give portable data representations

Damian Koncewicz18:09:45

How can I add 2 numbers from my Atom and pass it to the Sum ?? (defonce app-state (atom {:first-number 0 :second-number 0 :sum 0})) (defn sumNumbers [] #(swap! app-state assoc :sum (+ :first-number :second-number)) ) Or can anyone sent me a link where is article about it. Thank You!!


Is something else responsible for updating first/second number?


i wouldn't personally store the derived state in my atom. It makes it possible to get out of sync which can be a pain. but you could sum them by doing the following.

(defn sumNumbers []
 (swap! app-state update :sum #(+ (:first-number %) (:second-number %)))
editted to remove nested hash function

Damian Koncewicz19:09:43

responsible for numbers have inputs: [:input { :type "number" :class "number-Input" :value (:first-number @app-state) :on-change #(swap! app-state assoc :first-number (-> % .-target .-value)) }] 🙂

Damian Koncewicz19:09:12

And I want to make button to sum it and to show it 🙂


if you use 3 backticks (grave accent) before you paste code it comes across a bit nicer to read

Damian Koncewicz19:09:49

ok I will remember 🙂

Damian Koncewicz19:09:00

      :type "number"
           :class "number-Input"
      :value (:first-number @app-state)
      :on-change #(swap! app-state assoc :first-number (-> % .-target .-value))

Ferdinand Beyer19:09:02

(defn sumNumbers []
 #(swap! app-state assoc :sum (+ :first-number :second-number)) )
What's wrong with that? Isn't that exactly what you want?


nope. you need access to the value of :first-number so you need to use update instead of assoc

Chris G19:09:52

update is more inline with his intentions


and then provide an update fn that gets first

Damian Koncewicz19:09:15

I will learn 10000x more from You guys then from internet 🙂

Ferdinand Beyer19:09:20

Ah, now I understand what you mean

Ferdinand Beyer19:09:32

Well @U040ULRJL3B we are guys and girls from the internet

Damian Koncewicz19:09:00

@U922FGW59 You are guys and Girls from Slack 🙂

Martin Půda19:09:11

@U02SD8PATK2 your code

(defn sumNumbers []
 #(swap! app-state update :sum #(+ (:first-number %) (:second-number %)))
throws syntax error, it has nested #()s.


@U040ULRJL3B I would consider just derefing the numbers rather than the sum of the numbers that you synchronize. instead of (let [sum (:sum @app-state)]) do (let [sum (apply + ((juxt :first-number :second-number) @app-state))] or something similar

Chris G19:09:09

might have to be an explicit fn though

(defn sumNumbers []
 #(swap! app-state update :sum (fn [x] (+ (:first-number %) (:second-number %)))


thanks martin. the first #(swap! should just be (swap!

Ferdinand Beyer19:09:15

Tip: Embrace pure functions, and write this one first. And make sure it works:

(update-first-number current-state new-first-number)

Ferdinand Beyer19:09:09

Then you can use that in your event handler: #(swap! app-state update-first-number (.. % -target -value))

Damian Koncewicz19:09:50

Ok I see now I dont get it at all and I try to master making functions tomorrow 🙂 Thank You for Your time!! Have a good night


another option is to add a helper for getting target and just comping it and utilizing the update :first-number

(def evt->val #(-> % .-target .-val)
(partial swap! app-state update :first-number (comp + js/Number evt->val))

😍 1
Damian Koncewicz07:09:22

I made it!!

(defn sum-numbers []                             
   (swap! app-state assoc :sum(->  ( + (edn/read-string(:first-number @app-state )) (edn/read-string(:second-number @app-state ))))))

Damian Koncewicz07:09:51

And quick question is there any good tutorial on the net with ClojureScript? I would like to make some hard stuffs 😛

Martin Půda07:09:37

Is there any reason why you save your numbers as strings? You have to parse them with each call of sum-numbers. I suggest you to use helper by @U02SD8PATK2 and then just this function:

(defn sum-numbers []
  (swap! app-state assoc :sum (+ (:first-number @app-state)
                                 (:second-number @app-state))))

Damian Koncewicz09:09:37

this inputs saves numbers as a string [:input { :type "number" :class "number-Input" :value (:first-number @app-state) :on-change #(swap! app-state assoc :first-number (-> % .-target .-value)) }] I dont know yet why, but they do it. this is my atom: (defonce app-state (atom {:first-number 0 :second-number 0 :sum 0}))

Ferdinand Beyer09:09:22

HTML inputs (text fields) only deal with strings, yes. However, if you want to deal with numbers, it makes sense to convert the text input to a number in the on-change event. This gets more complicated quickly, as you need to validate that the text actually is a number, and decide what to do if not. Typical UI stuff. A good idea might be: • Keep the input text as string • Whenever it changes, try to parse it into a number (integer) • When parsing works: Store the parsed number in the state and do whatever you need to do (sum...) • Otherwise, you can give your user feedback that they need to change their input

Ferdinand Beyer09:09:55

Again, I recommend to break this down into smaller chunks, use pure functions to implement those, test these functions, then put them together. Instead of trying to do everything in one #(swap! ... assoc ...), make your event handler smaller by just calling swap! with a pure function and the current text input:

(defn update-text-input [state text-input]
  ;; This is a _pure_ function. Here you can:
  ;; - Save the text
  ;; - Convert to a number
  ;; - Compute sums
  ;; - ...
  ;; And return the updated state.

#(swap! app-state update-text-input (.. % -target -value))

Damian Koncewicz13:09:52

@U922FGW59 i found solution:

(defn numberInput [changeValue]
    [:input {:type "number" :value (changeValue @app-state) 
          :on-change (fn [e]
                        (let [new-value (js/parseInt (-> e .-target .-value))]
                          (swap! app-state
                                 (fn [data]
                                   (-> data
                                     (assoc changeValue new-value)

Damian Koncewicz13:09:17

is there any prettier for clojure in vsc??

Ferdinand Beyer13:09:24

Are you using Calva?

Damian Koncewicz13:09:36

when i have at last line something like this: )))))}] it's looking bad for me, but if it have to be like this I won't complain and just train coding more 🙂


@U040ULRJL3B i highly recommend getting used to the stacked parens and ending syntax. The style you posted above is c style code and you will not miss it when you get used to the stacked parens. I spent most of my 15 years of coding in c style languages and i know it is a bit hard to give up but I think you’ll be glad if you do.

Damian Koncewicz14:09:27

@U02SD8PATK2 Ok i will 🙂 Thank You for Your advice!! 🙂

❤️ 1
Ferdinand Beyer14:09:07

To me it is often also a sign of too complex code if you end up with a bunch of closing brackets

Ferdinand Beyer14:09:26

For instance,

(swap! app-state
    (fn [data]
        (-> data
            (assoc changeValue new-value)
Could be written as: (swap! app-state assoc changeValue new-value) Nesting level 1 instead of 4 🙂

Damian Koncewicz15:09:55

Nice 😄, I took it from tutorial and didn't think it have to be refactored

Ishaan Gupta21:09:12

What usually happens to namespaced keywords outside of a context that supports them? Remove the namespace? {:foo/a 1 :bar/b 2} -> {"a": 1, "b": 2} Keep the namespace as part of the key string? {:foo/a 1 :bar/b 2} -> {"foo/a": 1, "bar/b": 2} Nested context? {:foo/a 1 :bar/b 2} -> {"foo": {"a": 1}, "bar": {"b": 2}} Something else? I don't really know.


It depends on what the consumer needs.


If you're producing JSON from Clojure hash maps, most of the JSON libraries have settings to control this. We use org.clojure/data.json at work (pure Clojure, zero dependencies, fast enough for most use cases).


By default data.json drops the ns:

seanc@Sean-win-11-laptop:~/clojure$ clj -Sdeps '{:deps {org.clojure/data.json {:mvn/version "RELEASE"}}}'
Downloading: org/clojure/data.json/maven-metadata.xml from central
Downloading: org/clojure/data.json/maven-metadata.xml from sonatype
Clojure 1.11.1
user=> (require '[ :as json])
user=> (json/write-str {:foo/bar 1 :foo/quux 2})

Ishaan Gupta07:09:12

Is it better to work with strings of the whole namespace qualified keyword in case you've got a map like {:foo/a 1 :bar/a 2}?


Work with whatever is best for the consumer of the data - which use generally keywords within Clojure code.


yep. so for example, if you have necessary context in your namespace such that your data needs it to make sense then you can just convert it to a string in json which is valid.

  "filter/name": "some-name",
  "user/name": "some-user",
if you had some shape like this it wouldn't work to drop the ns.