In a pretty large data structure, I'd need to update a bunch of values. So given a set of keys #{:foo :bar :baz} that can be in unpredictable places in a data structure (but always keys in a map) I'd need to apply some function f to "update" the corresponding values. Is there some clojure.walk or such function that could help me do this?
I've not used it personally, but this sounds like the kind of problem https://github.com/redplanetlabs/specter might be useful for.
using clojure's walk fn you can check if a value is a MapEntry with the given key and update its value
walk + "a pretty large data structure" is not always the best combination if you care about performance
I thought pre/post/walk will feed my function the key and the value separately. Do those also pass in MapEntrys?
@lasse.olavi.maatta what else could I do?
I'm not saying there's some single obvious alternative, it depends on the situation if you can avoid walking. For example, in one situation I had code walking over several large but structurally static(!) datastructures. I split the walking into separate "find out what paths to update" and "actually update the value behind each path" steps and got like 50-200x speed up because the paths were static and I calculated them just once.
I usually try to think "why don't I know the exact paths to the values I need to alter". Could the producer of the data provide some extra information which I could use later to construct the paths, so that I don't have to resort to walking? But of course, this isn't always possible.
I see your point. update-in just gets so clumsy when there are vectors involved somewhere in the structure
Hello I am using tap> for printing strings from different core.async threads. This works quite well. That is until I put a for loop in a thread. The tap> inside a for loop doesn't seem to work. Is this standard behaviour? Or more likely I am being an idiot? The code I am trying out is as follows:
;; tap has been registered
(add-tap (bound-fn* clojure.pprint/pprint))
(go-loop [numbers (range 10 0 -1)]
(for [n numbers]
(do
( n))))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x7851a03f "clojure.core.async.impl.channels.ManyToManyChannel@7851a03f"]
Whereas the following seems to work
(go-loop [numbers (range 10 0 -1)]
(loop [n numbers]
(Thread/sleep 10)
(tap> (first n))
(when (pos? (count n))
(recur (rest n)))))
; 10
; 9
; 8
; 7
; 6
; 5
; 4
; 3
; 2
; 1
; nil
The reason I need to use a for loop inside a go-loop block is because otherwise I'll have to nest 2 loops and that is not allowed. Or is it?Also note there's nothing that prevents nesting for or doseq expressions; for simple cases you can even use the built-in iteration over multiple variables:
(for [a [1 2 3]
b [4 5 6]]
[a b])
;; => ([1 4] [1 5] [1 6] [2 4] [2 5] [2 6] [3 4] [3 5] [3 6])
(doseq [x [1 2 3]]
(doseq [y [4 5 6]]
(println [x y])))
;; => nil
;; but prints:
[1 4]
[1 5]
[1 6]
[2 4]
[2 5]
[2 6]
[3 4]
[3 5]
[3 6]
The default looping construct in Clojure, loop, also nests, though it's a bit peculiar due to how recur works:
(loop [outer 3]
(loop [inner outer]
(when (pos? inner)
(println inner)
(recur (dec inner))))
(when (pos? outer)
(recur (dec outer))))
;; => nil
;; but prints:
3
2
1
2
1
1Just noting that doseq supports the same syntax as for, so no need for nested doseq here - it can be a single doseq.
Yes; sorry if it wasn't clear, I just meant to show that there's nothing that prevents nesting.
there is no such thing as a for loop
I saw the documentation of clojure.core/for and that is what I am using...
is this wrong?
there is a for list comprehension that lazily builds a list. Which requires a consumer of that list
there is no such thing as a for loop in clojure core though
clojure.core/for
([seq-exprs body-expr])
Macro
List comprehension. Takes a vector of one or more
binding-form/collection-expr pairs, each followed by zero or more
modifiers, and yields a lazy sequence of evaluations of expr.This is from the example blurb
ClojureDocs Examples
via cider-nrepl
Example 1
To Rich Comment | To Output
;; prepare a seq of the even values
;; from the first six multiples of three
(for [x [0 1 2 3 4 5]
:let [y (* x 3)]
:when (even? y)]
y)
;;=> (0 6 12)
yes. there the replβs printer is forcing the realization of the list. What is forcing the realization in your example?
ok. Then do you have a way of nesting loops one inside the other?
functions usually
ok
I'll give it a try
Your example will work if you replace for with doseq. And then you also won't need that do.
@p-himik it did indeed
thanks!