Fork me on GitHub
#specter
<
2023-08-20
>
Lidor Cohen07:08:49

Hello everyone, if I wanna recursively traverse a structure just for a side effect what should I use? Is it select with view or something else?

Lidor Cohen09:08:30

I was reluctant of adding the word "recursively" because I knew that I'll get a link to recursive specter 😅 I know how to do recursion in specter, my question was mainly about the effects and recursion was more of a background information.

steveb8n09:08:19

It was inevitable 😂. We use recursive navs also. For side effects, could you use a command pattern to keep it pure? If so, you can reduce using the recursive nav.

steveb8n09:08:56

Not sure I understand what you mean by side effects in this case?

Lidor Cohen09:08:33

I want to print tuples of a map with each of it's value:

(do-some-magic {:a 1, :b 2}) =>
; [{:a 1, :b 2}, 1]
; [{:a 1, :b 2}, 2]

steveb8n09:08:09

Hmm, still don't have enough context to grok your problem. If trying to print a tree, we have done that using a zipper with side effects. Would that work?

Lidor Cohen09:08:37

Sure, i think...

Lidor Cohen09:08:30

I was reluctant of adding the word "recursively" because I knew that I'll get a link to recursive specter 😅 I know how to do recursion in specter, my question was mainly about the effects and recursion was more of a background information.

Lidor Cohen13:08:26

Hello again! 😊 I'm interested in writing a Specter code snippet that takes a list of maps as input and performs a merging operation using (conj []). The goal is to create a resulting map where each key holds a vector containing corresponding values from the input maps. To illustrate, the transformation should turn [{:a 1 :b 2} {:a 3 :b 4} {:a 5 :b 6}] into {:a [1 3 5], :b [2 4 6]}. As a bonus, if all the values within the input maps are themselves maps, I'd like to extend this behavior recursively. I've already implemented a solution for this using merge-with, but I wanted to try out the same process using Specter. This will also serve as an opportunity to compare the performance of the two approaches. Thanks in advance

phronmophobic16:08:08

I think you’ll get more responses if you explain what you tried, what worked, and what didn’t work.

Lidor Cohen17:08:41

Today I had an implementation of the sort:

(->> maps
     (select [ALL ALL])
     (group-by second)
     (transform [MAP-VALS] #(select [ALL LAST] %))
But it was way slower than the simple clojure implementation so I dropped that.

phronmophobic17:08:06

In general, I think you’ll get more of a benefit if you can make the the transformation in one step.

Lidor Cohen17:08:39

I did that as well using subselect and transformed, but it performed even worse. I think specter is just not a great fit for those kinds of transformations (+ reduce)

phronmophobic17:08:16

If you rewrite your spec version to not require the transformation after the group-by, that might help.

Lidor Cohen17:08:21

I tried to think of ways to do that using only specter but I couldn't find any, that's why I asked here for ideas 😅

phronmophobic17:08:55

Right, but you didn't include any of the methods you tried.

Lidor Cohen17:08:13

When I asked I wasn't able to think of any idea so there weren't any methods to write about. Only when I relaxed my constraints today (after I bumped) I wrote the attempt using group-by.

phronmophobic17:08:51

What's the reason behind wanting this particular transformation? Why does it need to be fast?

phronmophobic17:08:31

There are various libraries that have faster versions of group-by .

phronmophobic17:08:18

If you care about performance, then you'll probably want to do some amount of profiling.

Lidor Cohen17:08:54

It's a core operation in our code that is currently a performance bottleneck

Lidor Cohen17:08:33

We did profiling that's how we zeroed in on that code piece

Lidor Cohen17:08:35

But that code is already after performance refactoring so it might be solved.

phronmophobic17:08:18

The reason I ask is there are many ways to approach the problem and the solution will depend on these types of factors.

phronmophobic17:08:33

If you are still looking for alternatives, you can also look at https://github.com/cgrand/xforms and https://github.com/cnuernber/ham-fisted which both have alternate implementations of group-by that could help speed things up.

Lidor Cohen17:08:35

Actually the group-by implementation was way slower than another implementation of iterating on all the keys. And that was a bit slower than merge-with (that actually surprised me).

phronmophobic17:08:57

group-by, merge, and merge-with are not the fastest options which is why there are several alternate implementations.

Lidor Cohen17:08:46

ham looks very interesting and relevant to me, I'll try it. Thank you 🙏:skin-tone-3:

👍 1
Lidor Cohen19:08:41

Now I see ham only support clj (I need cljs) what a shame 😔

xificurC07:08:22

how would the recursive case look like?