I have a token scanner that simply returns nil for characters I'm not interested in. Rather than conj the nils to my token vector and then later stripping them all out, I want to simply not add them.
I'm using
;; dont conjoin if value false
(defn condj [v val]
(cond-> v, val (conj val)))
to do this. Is there a specific operator or a more concise implementation?
I believe you can use transducers for this. They are explained here. Our reducing function is conj and we construct a transducer (remove nil?) that turns this function into one that will ignore nil:
(def condj ((remove nil?) conj))
Note that remove is the opposite of filter. We can also implement condj using (filter some?), some? being a function that is true for any value except nil:
(def condj ((filter some?) conj))
It seems to work:
user=> (condj [3 4 5] 9)
[3 4 5 9]
user=> (condj [3 4 5] nil)
[3 4 5]
user=> (condj [3 4 5] false)
[3 4 5 false]
I like the cond-> version and often use that to avoid repetition in the if version. Don't forget to be explicit about false values, though. I also like to use Plumatic Schema to be explicit about the data shape entering and leaving the function:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[schema.core :as s]))
(s/defn condj :- [s/Any]
"Conjoin an item onto a vector of results if the item is not nil."
[accum :- [s/Any]
item :- s/Any]
(cond-> accum
(not (nil? item)) (conj item)))
(dotest
(let [result (-> []
(condj :a)
(condj :2)
(condj false)
(condj "four")
(condj nil)
(condj "last"))]
; nil is filtered but false is retained
(is= result [:a :2 false "four" "last"])))
You may also be interested in another version using my favorite library:
(s/defn condj :- [s/Any]
"Conjoin an item onto a vector of results if the item is not nil."
[accum :- [s/Any]
item :- s/Any]
(cond-it-> accum
(not-nil? item) (append it item)))
For more complicated forms, using the placeholder symbol it makes it explicit where the value is being threaded. I also like the convenience functions not-nil? and append since they also make the intent of the code plainer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With