Fork me on GitHub

Can I use threading macro expecting two arities on the first function? Something like this

(->> type coll
the filter-coll-by-type function would receive the coll and the type to filter.


or is it better to filter before and then use the filtered collection on the threading macro?


-- I was taking a look at the docs (, and found something that would work for me:

(defn get-total
  [coll m]
   (get-result coll m)
   (map #(:val %))
   (reduce +)))
Use a function "scope" to have the coll and type


What about just (->> coll (filter-coll-by-type type) (map-to-get-only-one-attribute) (join-into-string) ...) ?

๐Ÿ‘ 4

thanks @christian.gonzalez! it works for me! I made a PR with it: I'm just learning it and I don't if it is the best practice to use it that way. But thanks ๐Ÿ™‚


It is very common to use threading macros where the functions in the 'pipeline' have multiple arguments.


Is there a function that does the following: "zip" two seqs with a "gluing" function? For instance, (glue (fn [x y] (= (:id x) (:foo y))) xs ys) would then pair elements where :id and :foo are identical.


what result are you hoping to get if more than one element of xs has the same value of :id equal to BLARG, and more than one element of ys has the same value of :foo equal to BLARG?


If there were 5 elements in xs like that, and 10 elements in ys like that, do you want 5x10=50 pairs in the return value?


There are some similarities to what you asked about to clojure.set/join, but it probably isn't exactly what you want.


Doing a (group-by :id xs) and (group-by :foo ys) will give you two maps with keys equal to the values of those functions on xs and ys, and you could then merge-with them together with a custom merge fn.


Thanks, those suggestions were very helpful. My situation is a bit different, but reflecting about it with the above in mind led me to another solution: In my case I have a collection of id's and another collection containing items with id's (that needn't be in my first collection). But now I can either use the group-by approach or just filter first and then do what I want to do:


Nice. group-by is a good tool to have in the mental toolbelt.


I already use it a lot, but for some reason I didn't even remotely think of it this time ๐Ÿ™‚


Now I have a disgusting huge block of code that starts with (map (fn [id] (when-let [...] (let [...] (when-let [...] (if-let [...]. Is there a hint on what I can do to simplify such stacked whens and lets (such that I essentially return nil whenever a thing does not exist, but still need the name of the thing if it exists)?


@johb.maier check out better-cond ( for something that sticks close to clojure.core, or promenade if you want to try something a bit more different (

๐Ÿ‘ 4

ooh that's nice. I'm glad I'm not asleep yet so I got to see that


@johb.maier it's not as flexible as the above but some->/`some->>` can help there, combined with as-> if you need to refer back to the original at any point in the pipeline. more limited but it can also get the job done depending on what you're doing


@schmee That looks great, thanks. I will speak with my colleague on Monday to see if we will use this in the project.


just to note if you are reluctant to add dependencies is that both these projects have 0 dependencies of their own


@jesse.wertheim Ah yes, I tried it, but didn't get a nice result (I need many names, so I can't really thread much through any some-> without an as->).


I might be overlooking something though. What I take away from @schmee's proposed libraries is at least that such code can happen and isn't always easily simplifyable.


yeah it gets unwieldy again if you need the names a bunch of times throughout the pipeline, can't do things like (some-> {:b 2 :c 3 :d 4} (as-> m (or (:a m) (:b m))) (* 10))


it can definitely happen and it definitely gets annoying


@johb.maier we might be able to help clean it up if you want to share a snippet though. are you trying to remove items from the collection of id's based on whether the second collection has items with those ids, or..?


Let me see if I can break it down so that it's actually readable from the outside ๐Ÿ™‚


This is the gist of it I think. I hope the parens are alright.


I feel like the first when-let is the most problematic thing. I basically only want to map over those ids that I have items in all-items for (the names are bogus in the snippet).


And the (first (filter ... in that line looks very bad to me as well.


if you rewrite that with better-cond it will look just fine I think, give it a shot and see what you think


you can get rid of the let by doing (:foo ..) in the first when-let


@johb.maier what's item-2? the first item from the next id?


user=> (:foo nil)


@jesse.wertheim Oh, it comes from way above. Something that's also either there or nil.


@schmee Sorry I wasn't more specific: the name bindings I created are all used later on (no getting rid of those names) in the ... part.


But yes, I'm pretty sure it will look great with better-cond. I will try that Monday. It's good to know that it has no external dependencies.


I have an idea. I could do (map (fn [item] ...) loaded-items, where loaded-items are the items whose id's are present in all-items.


The resulting seq will contain fewer nil values, but that doesn't matter here.


this might be a horrible idea, but perhaps you might "transpose" the flow of data. Instead of mapping over the selected-ids, you might consider something like (->> all-items, (filter #(contains? selected-ids (:id %)), (do-something-with-selected-items), ...)?


@lasse.maatta I will think about it! It looks great flow-wise, but I guess I will miss the bindings in the last call.


Thanks for all the great input guys!


@johb.maier a lot of this can be cleaned up using these functions as transducer pipelines instead of seq functions too, like combining map and filter. and here's a custom distinct-by I've used before - it's just distinct that tracks uniqueness by the result of a predicate


@johb.maier that'll give you the first item for every ID, and then you can just compose it right with the map function, as I did in that example


the key to using it being lines 27-30 (the rest is ugly stuff just to set up the contrived example)


Transducers are not really on my radar yet. Does the above mean that map and filter are "combined" first before being let loose on a seq?


The distinct-by looks great for my example, thanks! I learned a lot today.


when you compose them, they turn into a single transducer - basically the map is passing its rf (reduce funciton) to that of distinct-by which is using it to supply values to map without ever having an intermediate structure


(this also makes it more performant)


you can't use the composed transducers on their own in that form - you would then use into, sequence, or (in the rare case you don't want any caching of results) eduction


(into [] (comp xf1 xf2 xdf3) some-col) is like doing (->> some-col (seq-fn1) (seq-fn2) (seq-fn3) (into []))`, but without all the wasted overhead on the lazy sequences


also cleaner, IMO. and no problem!