This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-02
Channels
- # announcements (2)
- # aws (13)
- # beginners (52)
- # boot (10)
- # calva (2)
- # cider (23)
- # clara (23)
- # cljs-dev (16)
- # cljsrn (5)
- # clojure (69)
- # clojure-brasil (1)
- # clojure-conj (3)
- # clojure-dev (41)
- # clojure-india (2)
- # clojure-italy (39)
- # clojure-nl (5)
- # clojure-russia (2)
- # clojure-spec (5)
- # clojure-uk (51)
- # clojurescript (78)
- # code-reviews (13)
- # data-science (2)
- # datascript (22)
- # datomic (47)
- # duct (13)
- # emacs (4)
- # figwheel-main (45)
- # fulcro (85)
- # funcool (4)
- # jobs (9)
- # nrepl (106)
- # off-topic (5)
- # pathom (7)
- # pedestal (2)
- # re-frame (17)
- # reagent (32)
- # reitit (7)
- # ring-swagger (2)
- # shadow-cljs (33)
- # spacemacs (4)
- # specter (2)
- # tools-deps (203)
- # vim (1)
Can I use threading macro expecting two arities on the first function? Something like this
(->> type coll
(filter-coll-by-type)
(map-to-get-only-one-attribute)
(join-into-string)
...)
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 (https://clojuredocs.org/clojure.core/-%3E%3E), 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) ...)
?
thanks @christian.gonzalez! it works for me! I made a PR with it: https://github.com/LeandroTk/pokemon/pull/1 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 when
s and let
s (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 (https://github.com/Engelberg/better-cond#minimizing-rightward-drift) for something that sticks close to clojure.core, or promenade if you want to try something a bit more different (https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md#a-simple-example)
@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))
@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 ๐
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).
if you rewrite that with better-cond it will look just fine I think, give it a shot and see what you think
@johb.maier what's item-2? the first item from the next id?
@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
.
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.
@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 https://repl.it/@jaawerth/distinct-by
@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?
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
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