Fork me on GitHub
#specter
<
2018-01-06
>
chromalchemy11:01:46

What's a good way to conditionally add/remove a value based on whether it's already in a collection? Basically like assoc or dissoc for vectors, based on value instead of index. Example: If :a is not it in [:b :c], add it, else remove it.

chromalchemy11:01:20

I want to reach for if-path but don't think I can use setval with that to conditionally set :a or NONE

chromalchemy11:01:09

Or should I just stick to using maps?

chromalchemy11:01:37

I'm trying to filter some items on some keywords, and I wanted to avoid having {:a true :b false} or {:a nil :b :nil} cluttering my data up. I feel like map values are redundant, because I can get boolean truthiness by testing for the presence of keywords (in maps at least).

chromalchemy12:01:09

Probably I should use a set instead of a vector. But don't think that deserializes from Firebase properly, which is what I'm using for persistence.

chromalchemy13:01:07

@nathanmarz Thank. Can I use multi-transform with if-path?

chromalchemy13:01:26

instead of multi-path in the examples...

chromalchemy13:01:48

right now I'm hung up on:

(select
    (if-path (= 1 2) ; false condition
      [ALL (pred= :a)]
      [ALL (pred= :c)])
    [:a :b :c])
=> [:a]

chromalchemy13:01:22

Doesn't seem to want to return the second path, based on the negative condition

chromalchemy13:01:59

Oh I think I see. It must be a conditional-path, not a generic condition...

chromalchemy14:01:54

This is working!

(multi-transform
  (if-path
    [ ALL (pred= :a)]
    [ ALL (pred= :a) (terminal-val NONE)]
    [ BEFORE-ELEM (terminal-val :a)])
  [:a :b :c])

chromalchemy14:01:45

Do you think I am barking up the wrong tree performance-wise to use keywords in vectors this way? The set of keywords will be pretty small, so I hope sequential lookup with (pred=) is not too big a drag.

nathanmarz14:01:15

@chromalchemy if ordering isn't important, then using a set or multi-set would be much more natural

schmee21:01:08

hmm… am I doing something wrong here or is this supposed to work?

user=> (def data {:a [:x] :b [:x :x] :c [:x :x :x]})
#'user/data
user=> (select [MAP-VALS (view count)] data)
[1 2 3]
user=> (reduce + (traverse [MAP-VALS (view count)] data))
6
user=> (transduce (traverse-all [MAP-VALS (view count)]) + 0 data)
ClassCastException clojure.lang.Keyword cannot be cast to java.util.Map$Entry  clojure.lang.APersistentMap$ValSeq.first (APersistentMap.java:234)

nathanmarz22:01:38

traverse-all runs on each item of sequential input

nathanmarz22:01:57

@schmee which is why is has the -all suffix

nathanmarz22:01:11

that's generally what transducers do

schmee22:01:52

ok, I think I see the difference now

schmee22:01:54

so traverse-all can be transduced but traverse is reducible but not transducible?

schmee22:01:21

if that makes any sense

nathanmarz22:01:23

traverse-all creates a transducer

nathanmarz22:01:30

traverse returns a reducible object

nathanmarz22:01:04

traverse-all exists to integrate specter with transducers

schmee23:01:20

gotcha, thanks for clarifying 👍