specter

2024-02-05T11:54:07.639709Z

Hello 👋 I'd like to transform and maybe filter in one go, some thing like this:

(sp/transform [sp/INDEXED-VALS]
                (fn [[i x]] (let [v (some-fn x)]
                              (if (some-pred v) [i v] sp/NONE)))
                [1 2 3 4])
is this possible in specter?

rolt 2024-02-05T17:18:24.608569Z

you're not using i ?

2024-02-05T18:03:01.048649Z

In what? I return i and v

2024-02-08T08:34:45.164089Z

thank you @rolthiolliere I did some benchmarking on a couple of options and this is what cameout:

(timeit
   10000
   (sp/select [sp/INDEXED-VALS
               (sp/view (fn [[i x]] (let [v (inc x)]
                                      (if (even? v) none [i v]))))
               (sp/pred #(-> % none? not))]
              (vec (range 100)))) := 1150

  (timeit
   10000
   (sp/multi-transform [(sp/view #(map-indexed vector %))
                        sp/ALL
                        (sp/view (fn [[i x]] (let [v (inc x)]
                                               (if (even? v) none [i v]))))
                        (sp/if-path (fn [[i x]] (-> x none? not))
                                    (sp/terminal identity)
                                    (sp/terminal-val sp/NONE))]
                       (vec (range 100)))) := 1725


  (timeit
   10000
   (reduce-kv
    (fn [acc i o]
      (let [v (inc o)]
        (if (even? v)
          acc
          (conj acc [i v]))))
    []
    (vec (range 100)))) := 445

rolt 2024-02-06T15:23:19.802559Z

yes but you're not doing anything with it

rolt 2024-02-06T15:26:17.260539Z

maybe use actual function with the expected result ?

rolt 2024-02-06T15:26:28.404019Z

because I'm not sure I understand the intent

2024-02-06T15:26:58.021259Z

What do you mean? it changes the data. I want it in the overall data for later computations

2024-02-06T15:27:56.180549Z

I want to know the original position of each transformed value in case it passes the pred

rolt 2024-02-06T15:28:05.192459Z

(sp/transform [sp/INDEXED-VALS] (fn [[i x]] [i x]) [1 2 3 4]) => [1 2 3 4], not [[0 1], [1 2] ...]

rolt 2024-02-06T15:28:33.871349Z

oh there's an other path later ?

2024-02-06T15:28:50.291149Z

No

rolt 2024-02-06T15:29:16.091399Z

sp/transform [INDEXED-VALS the-filter-transformer somthing-else] ?

2024-02-06T15:31:04.857539Z

Currently I can't test that but i think it did return the values with the indices but when I introduced the NONE in order to omit values it throws (something about keyword I'm guessing it tries to do something to NONE)

rolt 2024-02-06T15:32:30.802229Z

that's because it would expect [i NONE]

rolt 2024-02-06T15:33:15.549429Z

but even then I think it throws

rolt 2024-02-06T15:33:23.769629Z

[i nil] would work

rolt 2024-02-06T15:37:56.308089Z

now I see the intent but I'm not sure how you would do that

2024-02-06T15:38:02.444309Z

My code is performance critical so I'm trying to do the transformation and the filtering in one go. My current implementation is with reduce-kv so if I'm not surpassing that it won't do. If I compare only the transformation without the filtering, specter wins (probably because of transient). Then I tried to add the filtering using NONE and failed

rolt 2024-02-06T15:38:40.243699Z

I may have an idea let me try

🙏 1
rolt 2024-02-06T15:52:28.207999Z

no can't find it, once you use INDEXED-VALS, when you "leave" you're returning the whole vector. And using view + map-indexed would defeat the purpose

rolt 2024-02-06T16:22:55.436079Z

I cooked this abomination: (sp/multi-transform [(sp/view #(map-indexed vector %)) sp/ALL (sp/view (fn [[i x]] [i (some-fn x)])) (sp/if-path (fn [[i x]] (some-pred x)) (sp/terminal identity) (sp/terminal-val sp/NONE))] [1 2 3 4])

rolt 2024-02-11T13:33:34.817759Z

if you're going to use clojure why not use transducers ?

(into [] (comp (map inc) (filter even?)) ...)

2024-02-11T13:34:04.183479Z

Might also be perfomant