Fork me on GitHub
Pragyan Tripathi04:08:11

I am trying to merge vector of maps. I tried doing it using the reduce method but unable to retrieve the expected result. Input data:

(def data ([{:padding-top "30px"} {:padding-top "40px"} {:padding-top "50px"}] [{:margin "40px"}]))

(defn merge-data
Expected Output:
(merge-data data)

({:padding-top "30px" :margin "40px"}
  {:padding-top "40px"}
  {:padding-top "50px"})


The input data is a list of two vectors, each of which contains maps.

Pragyan Tripathi04:08:08

yes that’s correct. coming from JS background I am just thinking using something like forEach. But I am trying to figure out how to do it in more functional way.


So you have two vectors of maps, we can call the first vector's elements [a1 a2 a3 ...] and the second vector's elements [b1 b2 b3 ...], and these two vectors might have different numbers of maps in them.


You want to return a single list or vector of maps which contain [(merge a1 b1) (merge a2 b2) (merge a3 b3) ...], and if one vector runs out of maps before the other one, just return those maps?

Pragyan Tripathi05:08:24

that’s absolutely right

Pragyan Tripathi05:08:27

there is one more problem the vector elements can be more. [a1, a2, a3…], [b1, b2, b3], [c1, c2, c3]… etc…

Pragyan Tripathi05:08:45

merging should happen on the basis of indices only. [(merge a1 b1 c1) (merge a2 b2 c2)….]


If the N vectors were all of the same length, or you were willing to stop with the shortest one, then (apply map merge list-of-vectors) would do it.


because (map merge list1 list2 list3) does what you want for 3 lists/vectors/sequences of maps, and (map merge list1 list2 list3 list4) does what you want for 4 sequences of maps, etc. apply will handle any number of such lists in the list-of-vectors argument.


but if you want the result to have maps for the longest of the lists, and they can be of different length, then that does not quite do what you want.

Pragyan Tripathi07:08:48

thanks a lot @U0CMVHBL2 this advice really helps.. Will implement the solution and update you.

Pragyan Tripathi04:08:01

Thanks andy with your help I was able to solve the problem I was having with following code:

(defn merge-styles
  [& args]
  (let [max-count (apply max (map #(count %1) args))
        items (map #(take max-count (concat %1 (repeat nil))) args)]
    (apply map merge items)))
Thanks again for your advice.

Godwin Ko04:08:52

Any pattern on processing a large map within a data processing pipeline, with each step in the pipeline add additional scoped key/value pair into the map? I found it hard to trace the logic, as each pipeline transformation functions must be declared before the main processing pipeline function, it’ll be confusing quickly if the map entries is large and over 3/4 transforming steps… 😅

Ashley Smith10:08:08

im getting really stressed with this HTML escaping stuff 😞 I have a markdown file that is creating HTML (and right now I'm trying markdown->hiccup code), but I want to ensure that any HTML the user writes is NOT executed, but stuff created by markdown is. It's pretty frustrating because: - If I attempt to sanitise it before processing, code blocks in MD show the escape html and it looks ugly - If I sanitise it after, it sanitises the HTML produced by my markdown translator - If I use, the compiler actually translates HTML written by the user into hiccup for them. I imagine this is because it goes markdown string -> html string -> hiccup data. I really don't know how to do this, but its such a common pattern. I can write <button> button </button> here and it looks just fine, no escaping, and yet writing <button> button </button> here doesn't get rendered. What's the solution?

Ashley Smith11:08:17

I even followed the example on the readme, but the result is the OPPOSITE of what I wanted.

(-> (:post-summary p)
                  (md/md->hiccup {:encode? true})
Pros: It doesn't escape HTML produced by markdown and so hiccup works like normal Cons: For some reason, it appears to escape HTML AFTER converting to hiccup, meaning that the badbutton code is no longer HTML anymore.

Ashley Smith12:08:45

I actually did get it working using markdown-clj, my error previously was that I didn't know state was a map, so I got it. However, my single-line code blocks aren't quite working. Let me show some code

Ashley Smith12:08:16

                    {:__html  (md/md->html 
                                  (:post-summary p)
                                  (cons escape-html mdt/transformer-vector))}}]

(defn- escape-html
  "Change special characters into HTML character entities."
  [text state]
  (let [sanitized-text 
          (clojure.string/escape text 
             {\& "&amp;" 
              \< "&lt;" 
              \> "&gt;" 
              \" "&quot;"
              \' "&#39;"})]
    [(if (not (or (:code state) (:codeblock state)))
      sanitized-text text) state]))

Ashley Smith12:08:57

It looks okay apart from the inline code.

Ashley Smith12:08:21

I'm not also trying to get highlight.js to work, but that doesn't seem to do anything going off of their usage page


Hi y'all I'm having hard time figuring out if what i'm reading is current or not, what would be the recommended source for documentation??


specially for clojurescript


@gonzalo.romano I've used this in the past you can change the version to make sure you stay up to date with what you're working with You may also be interested in

Ashley Smith18:08:38

(set! (.-style.background-color e) "transparent")
Is this how I'd go about changing something's colour to transparent using clojurescript interop?

Ashley Smith18:08:24

Ah I got it actually!

(aset e "style" "background-color" "transparent")

Ashley Smith18:08:04

I didn't know that doing .-style returned another object that you had to get properties of

Ashley Smith18:08:13

I thought style.background-color was the property

Ashley Smith18:08:18

that was quick 🙂


I am doing this exercise: The loops seem to be ending early. In diagonal-collision? I want to go through each queen in an "outer" recursion, checking that queen with each other queen in the "inner" recursion. But the entire thing stops after a few iterations.


there's no implicit looping, so there's likely a case where you should recur but don't, or you recur in a way that skips cases -- I don't quite understand the code well enough to tell you precisely where it goes wrong


it would help to make things simpler, for example (first (drop 1 x)) is idiomatically (second x) or (nth x 1)


also the code might be more straightforward with a hash-map from number to number, instead of a vector which requires finding an index via scan


though I guess this is a two way mapping, so a vector might still be simpler


also the pattern used comparison likely has a better higher order equivalent, eg. (for [q1 queens q2 queens :when (not= q1 q2)] ...)


(for is a comprehension and not a looping construct, it generates a lazy-seq)


this gets the x/y for each item, and gets all possible pairs as a lazy-seq

user=> (let [queens (map list (range) [5 8 2 3 7 1 3 6])] (for [q1 queens q2 queens :when (not= q1 q2)] [:comparing q1 q2]))
([:comparing (0 5) (1 8)] [:comparing (0 5) (2 2)] [:comparing (0 5) (3 3)] [:comparing (0 5) (4 7)] [:comparing (0 5) (5 1)] [:comparing (0 5) (6 3)] [:comparing (0 5) (7 6)] [:comparing (1 8) (0 5)] [:comparing (1 8) (2 2)] [:comparing (1 8) (3 3)] [:comparing (1 8) (4 7)] [:comparing (1 8) (5 1)] [:comparing (1 8) (6 3)] [:comparing (1 8) (7 6)] [:comparing (2 2) (0 5)] [:comparing (2 2) (1 8)] [:comparing (2 2) (3 3)] [:comparing (2 2) (4 7)] [:comparing (2 2) (5 1)] [:comparing (2 2) (6 3)] [:comparing (2 2) (7 6)] [:comparing (3 3) (0 5)] [:comparing (3 3) (1 8)] [:comparing (3 3) (2 2)] [:comparing (3 3) (4 7)] [:comparing (3 3) (5 1)] [:comparing (3 3) (6 3)] [:comparing (3 3) (7 6)] [:comparing (4 7) (0 5)] [:comparing (4 7) (1 8)] [:comparing (4 7) (2 2)] [:comparing (4 7) (3 3)] [:comparing (4 7) (5 1)] [:comparing (4 7) (6 3)] [:comparing (4 7) (7 6)] [:comparing (5 1) (0 5)] [:comparing (5 1) (1 8)] [:comparing (5 1) (2 2)] [:comparing (5 1) (3 3)] [:comparing (5 1) (4 7)] [:comparing (5 1) (6 3)] [:comparing (5 1) (7 6)] [:comparing (6 3) (0 5)] [:comparing (6 3) (1 8)] [:comparing (6 3) (2 2)] [:comparing (6 3) (3 3)] [:comparing (6 3) (4 7)] [:comparing (6 3) (5 1)] [:comparing (6 3) (7 6)] [:comparing (7 6) (0 5)] [:comparing (7 6) (1 8)] [:comparing (7 6) (2 2)] [:comparing (7 6) (3 3)] [:comparing (7 6) (4 7)] [:comparing (7 6) (5 1)] [:comparing (7 6) (6 3)])


the (map list (range) [...]) construct pairs up an index with a value at that index


this still returns each pair twice in flipped order though


Ah, a list comprehension should be much better. I didn't really like my function that went through everything, but I also didn't want to rethink it before I got it working, since I have no idea why it doesn't work.


Thank you, I need to take some time to read through what you wrote 🙂

👍 4

This is what I ended up with, thank you! Only thing I'm confused about is (map list (range) qs)). How does it work?


map takes a function plus any number of collections


it calls the function on the first element of each coll, then the next item on each, etc. until one of them ends


user=> (map list [:a :b :c] '[dog cat cow elephant])
((:a dog) (:b cat) (:c cow))


range returns numbers from 0 on - without any args it returns an indefinite series of numbers


don't use def inside defn - unlike in scheme, def always creates a global


use let instead


also, instead of the low level .contains method, the usual approach would be to use (some true? collisions) - that returns true for the first collision it finds (and stops realizing the lazy seq at that point, no need to calculate more results)


Oh, thank you! I was wondering why I never saw people use def inside functions.


Thing about range makes sense too. Thank you, starting to really enjoy clojure


I have an async channel adapted from a node event emitter. I have a function which pushes events from the emitter to a channel - but there is also a method cancel to stop the event emitter. The event emitter basically subscribed to ongoing changes and when one wants to stop listening one has to cancel the subscription. Now, my question is how I would best design the function to be able to get a channel but still be able to cancel the subscription. Should I return an array as [cancel-fn channel] or is there a way to only return the channel and make the (close! channel) also cancel the subscription?


the publisher gets a result, true or false when writing to the channel, false means the channel is closed


assuming you are using put! the result is passed to the fn1 callback you pass in


I might want to instead use two channels to get full duplex communication between things, because closing a channel isn't something you can wait for


the problem with relying on closing the channel is the sender won't find out the channel is closed until the sender tries to send something, which not always acceptable


Yes, this is nothing I want to rely on


>I might want to instead use two channels to get full duplex communication between things Can you maybe elaborate on this? What would the second channel be for? I currently fail to see the use 😞


instead of having a single channel that events flow from producer to consumer through, you have two channels, one that events flow from producer to consumer through and one that the consumer can use to signal that it is done consuming to the producer


basically the same thing has a channel + cancel-fn but using a channel instead of a fn (maybe some day consumers will have other information they want to convey to producers and this new control channel would be a way to do it)


@hiredman Thats an interesting idea and I'd consider it if I was in control of the producer - but the producer is PouchDB and the cancel method is also delivered by the PouchDB API so I think using the function for closing should be fine