What is the API for PersistentQueue? - data-structures

What is the API for PersistentQueue?
Naïvely, it appears to lose any data put into it:
user=> (def q (into (clojure.lang.PersistentQueue/EMPTY)
(repeat 5 nil)))
#'user/q
user=> (def q2 (pop (conj q :a)))
#'user/q2
user=> (get q2 4)
nil
user=> (get q2 0)
nil
I must not be accessing PersistentQueue correctly. Clearly it doesn't work with get. What is the right way to access a PersistentQueue? What can you do with it?
And is PersistentQueue documented anywhere, even informally? ("It's only fully documented in my answer" is fine. Really, I'm hoping that someone will write the missing documentation in an answer, or tell where to find it if it's not missing.)

conj never mutates its argument, it returns a new data structure that is immutable, and may share data internally with the original. But I think you know this part already.
get only works on associative data, and returns nil rather than an error if used on non-associative data. queues are not associative. This issue is masked partially in your example by putting nil into the queue, which makes the nil returned by get ambiguous.
user=> (def q (into clojure.lang.PersistentQueue/EMPTY (repeat 5 :a)))
#'user/q
user=> (into [] q)
[:a :a :a :a :a]
user=> (def q2 (pop (conj q :b)))
#'user/q2
user=> (into [] q2)
[:a :a :a :a :b]
user=> (get q2 4)
nil
user=> (get q2 0)
nil
user=> (nth q2 4)
:b
user=> (nth q2 0)
:a
Typically the right operations to use with a queue are conj, into, peek, and pop.
user=> (def q3 (-> q2 (pop)
(conj :c :d)
(pop)
(conj :e)
(pop)
(pop)
(conj :f)))
#'user/q3
user=> (into [] q3)
[:b :c :d :e :f]
user=> (peek q3)
:b

The protocol for sequential collections is
(conj coll x) - return collection coll with x added to one end or the other;
(peek coll) - return the next item to be discarded from coll, if there is one;
(pop coll) - return coll less the discarded end.
peek and pop always work at the same end:
the front of a list (or general sequence);
the back of a vector or queue.
conj works at the same end as peek/pop of a vector or list, but at the opposite end (the front) of a queue. That's what makes it work as a queue.
As has been said, get and disj have nothing to do with sequential collections.
You may be puzzled because a PersistentQueue doesn't know how to properly convert itself into a string. seq will show you what you've got. For instance,
(def q (into (clojure.lang.PersistentQueue/EMPTY)
(repeat 5 nil)))
q ;=>#<PersistentQueue clojure.lang.PersistentQueue#1b4d89f>
(seq q) ;(nil nil nil nil nil)

Related

[Little Schemer Ch3 pp.34 & 37]: Why (rember a (cdr lat)) as the 2nd argument of cons interpreted as unknown on p.37 example

I run both example on p.34 and p.37 using DrRacket debug mode step by step. And below are the stack windows results when processing (cdr lat) the first time of both examples.
p.34, the failed example without cons
(define rember
(lambda (a lat)
(cond
((null? lat) '())
(else (cond
((eq? a (car lat)) (cdr lat))
(else (rember a (cdr lat)))
)))))
(rember 'c '(a b c d))
Stack area in debugger:
(cdr …)
(rember …)
p.37 with cons on last line:
(define rember
(lambda (a lat)
(cond
((null? lat) '())
(else (cond
((eq? a (car lat)) (cdr lat))
(else (cons (car lat)
(rember a (cdr lat)))))))))
(rember 'c '(a b c d))
Stack area in debugger:
(cdr …)
(rember …)
(rember …)
The Stack area with p.37's code indicates that the second call of rember has been classified as unknown before processing (cdr lat).
The only difference of 2 examples is p.37 added "cons". Cons takes 2 arguments, a s-expression and a list.
Without (cdr lat), rember itself doesn't return the list. And all the examples containing (cdr lat) within the first 40 pages of the book all have the same (function (cdr variable) format.
I don't understand why p.37 example rember itself being identified as unknown and justified for pending reduction while the contained (cdr lat) can be processed.
Or why rember in the position of 2nd argument of cons being interpreted that way.
Thanks!
TL;DR: what you see (and misinterpret) is the stack of function calls, and the effects of tail recursion.
To answer your specific question about the debugger: your interpretation is wrong. What you see there is the run-time stack of function calls that got you to that specific point in execution timeline where you're at right now.
It is not "unknown", not something "to be reduced later". You've already came through it, to your current execution point. What it is, is awaiting the results from the nested invocation, to continue doing its work with the results.
If you click on Step few more times (with the p.37 code), you'll get to a deeper point where you'll see even more (rember)s appear in the Stack area. Your current execution point appears top-most on the Stack; the earliest – bottom-most.
Notice the Variables area shows the variables' values for that specific invocation frame.
If you move your mouse cursor and hover over a lower (rember) and click on it, you'll see its variables' values:
Racket's debugger gets a bit getting used to.
Also do notice the "last evaluated value" field in the top left corner shown in very small letters (in the previous image). This is a very important and useful piece of information, while debugging. It could use being a little bit more visible on the screen.
The reason you don't see the stack of (rember)s grow with the first code (p.34),
is that it is tail recursive. There is nothing to be done with the result of the deep nested invocation of rember except to return it further back; so there's no need to save any state for that. This means the invocation frame for rember gets reused, replaced, and that's why you only ever see one of them, at the bottom of the Stack.
But with the p.37's code there's more stuff to be done with the returned value - a preceding list element must be consed onto the result. This means that list element must be preserved, remembered somewhere. That somewhere is rember's invocation frame where that list element was accessed as (car lat), for that value of lat, at that point in execution timeline.
Similarly, for all the other functions that have (else (function (cdr ... pattern, this means they are tail-recursive too. But if you see something like (else (cons ... (function (cdr ..., then they are not. The cons is in the way.
To better see what's going on, we rewrite it in an equational pattern-matching pseudocode:
(rember34 a lat) =
{ (null? lat) -> '()
; (eq? a (car lat)) -> (cdr lat)
; else -> (rember a (cdr lat))
}
This further simplifies to three clauses,
rember34 a [] = []
rember34 a [a, ...as] = as
rember34 a [b, ...as] = rember a as
Is this pseudocode understandable enough just visually, without being explicitly explained? I hope that it is. The other definition is
rember37 a [] = []
rember37 a [a, ...as] = as
rember37 a [b, ...as] = [b, ...rember a as]
Now just by looking at these definitions we can see the difference, and what each one does.
The first, rember34, goes along the list (which is its second argument), (3rd clause) until it finds a in it (its first argument), and if it does (2nd clause), it returns the rest of the list at that point. If there was no a found (3rd clause) and we've reached the end of the list (1st clause) so that the list to continue along is now empty ([]), the empty list [] is returned (1st clause).
Makes sense. For example,
rember34 3 [1,2,3,4,5] % Tail-Recursive Call:
= rember34 3 [2,3,4,5] % Just Returning The Result...
= rember34 3 [3,4,5] % Call Frame Is Reused.
= [4,5]
rember34 3 [1,2]
= rember34 3 [2]
= rember34 3 []
= []
The second, rember37, does the same but with one crucial difference: it keeps each non-matching element before the one that it finds and removes (as before). This means that if there was no such element found, the same list will be recreated. For example,
rember37 3 [1,2,3,4,5]
= [1, ...rember37 3 [2,3,4,5]] % the->
=> [2, ...rember37 3 [3,4,5]] % stack->
<= [4,5] % grows
<= [2,4,5] % <-and
= [1,2,4,5] % <-contracts
rember37 3 [1,2]
= [1, ...rember37 3 [2]] % must remember 1,
=> [2, ...rember37 3 []] % and 2, to be used
<= [] % after the recursive call
<= [2] % has returned its result
= [1,2] % to its caller
Hopefully this clarifies things.
a sidenote: under the tail-recursion modulo cons optimization, it'd be
rember37 3 [1,2,3,4,5]
= [1, ...rember37 3 [2,3,4,5]]
= [1, ...[2, ...rember37 3 [3,4,5]]]
= [1,2, ...rember37 3 [3,4,5]]
= [1,2, ...[4,5]]
= [1,2,4,5]
rember37 3 [1,2]
= [1, ...rember37 3 [2]]
= [1, ...[2, ...rember37 3 []]]
= [1,2, ...rember37 3 []]
= [1,2, ...[]]
= [1,2]
which is much like it'd be under lazy evaluation as well!
Let me strongly suggest that you use the stepper here, and not the debugger. I think you'll see a more consistent set of reduction rules. Specifically, I don't think you'll see anything "identified as unknown."
To use the stepper: Open a fresh buffer, make sure the language level is set to beginning student with list abbreviations, and paste the definition and the call into the definitions window. Click on "step". I think you'll see the difference between the two evaluations pretty quickly.
Please ask followup questions if anything doesn't make sense!

Faster/more idiomatic way to achieve a "map-when"?

I would like to implement a function which maps over a sequence of maps and update values when predicates match
Here is a first working draft :
(defn update-if
([m k pred f]
(let [init (get m k)]
(if (and (not-nil? init) (pred init))
(update m k f)
m)))
([m bindings]
(reduce-kv
(fn [agg k v]
(let [[pred f] v]
(update-if agg k pred f)))
m bindings)))
(update-if {:a 1 :b 2} {:a [even? inc] :b [even? dec]}) ;; ==> {:a 1 :b 1}
(update-if {:a 1 :b 2} :b even? dec) ;; ==> {:a 1 :b 1}
(defn map-when
"Walks a collection of associative collections
and applies functions based on predicates
Output :
(map-when {:a [even? inc] :b [nan? zero]} '({:a 1 :b NaN} {:a 2 :b 7} {:a 4 :b NaN}))
=
({:a 1 :b 0} {:a 3 :b 7} {:a 5 :b 0})"
([bindings data]
(reduce
(fn [acc row]
(conj acc (update-if row bindings)))
'() data))
([pred f data]
(map
(fn [x]
(if (and (not-nil? x) (pred x))
(f x)
x))
data)))
Not-nil? check is important (here) because it just means data is missing.
The function takes around 2s to perform this on 1 million random {:a :b} maps (random gen included) .
I feel odd that no function exists for this in core/core-related library.
Are there some performance hints to improve this ? I tried transient but it does not work on empty lists '()
Thanks
You should look at the specter library. It probably has what you are looking for. Example:
(def data {:a [{:aa 1 :bb 2}
{:cc 3}]
:b [{:dd 4}]})
;; Manual Clojure
(defn map-vals [m afn]
(->> m (map (fn [[k v]] [k (afn v)])) (into {})))
(map-vals data
(fn [v]
(mapv
(fn [m]
(map-vals
m
(fn [v] (if (even? v) (inc v) v))))
v)))
;; Specter
(transform [MAP-VALS ALL MAP-VALS even?] inc data)
Generate just the necessary lambda to maximize reusability.
(defn cond-update-fn [clauses]
(fn [m]
(reduce (fn [m [k [pred f]]]
(cond-> m
(and (contains? m k)
(pred (get m k))) (update k f)))
m
clauses)))
If your preds and fns are known at compile time writing a macro instead (left as exercise for the reader) gives higher performance because of no pred iteration overhead.
Reuse in any context:
(def input [{:a 42, :b 42} {:a 42,:b 43}])
(def cond-update
(cond-update-fn {:a [even? inc]
:b [odd? dec]}))
(map cond-update input)
;-> ({:a 43, :b 42} {:a 43, :b 42})
;; Transducer
(into [] (map cond-update) input)
;-> [{:a 43, :b 42} {:a 43, :b 42}]
;; Standalone
(cond-update {:a 32})
;-> {:a 33}

How to remove sequential matches in vector in Clojure?

Let's say I have a vector ["a" "b" "c" "a" "a" "b"]. If given a sequence ["a" "b"], how can I remove all instances of that sequence (in order)? Here, the result would just be ["c" "a"].
If sequences that need to be removed are known in advance, core.match may be useful for your task:
(require '[clojure.core.match :refer [match]])
(defn remove-patterns [seq]
(match seq
["a" "b" & xs] (remove-patterns xs)
[x & xs] (cons x (remove-patterns xs))
[] ()))
(remove-patterns ["a" "b" "c" "a" "a" "b"]) ;; => ("c" "a")
The short answer is to treat it as a string and do a regex remove:
(defn remove-ab [v]
(mapv str (clojure.string/replace (apply str v) #"ab" "")))
(remove-ab ["a" "b" "c" "a" "a" "b"])
=> ["c" "a"]
The long answer is to implement your own regex state machine by iterating through the sequence, identifying matches, and returning a sequence without them.
Automat can help with making your own low level regex state machine:
https://github.com/ztellman/automat
Instaparse can be used to make rich grammas:
https://github.com/Engelberg/instaparse
You don't really need a library for such a small match, you can implement it as a loop:
(defn remove-ab [v]
(loop [[c & remaining] v
acc []
saw-a false]
(cond
(nil? c) (if saw-a (conj acc "a") acc) ;; terminate
(and (= "b" c) saw-a) (recur remaining acc false) ;; ignore ab
(= "a" c) (recur remaining (if saw-a (conj acc "a") acc) true) ;; got a
(and (not= "b" c) saw-a) (recur remaining (conj (conj acc "a") c) false) ;; keep ac
:else (recur remaining (conj acc c) false)))) ;; add c
But getting all the conditions right can be tricky... hence why a formal regex or state machine is advantageous.
Or a recursive definition:
(defn remove-ab [[x y & rest]]
(cond
(and (= x "a") (= y "b")) (recur rest)
(nil? x) ()
(nil? y) [x]
:else (cons x (remove-ab (cons y rest)))))
Recursive solution for a 2-element subsequence:
(defn f [sq [a b]]
(when (seq sq)
(if
(and
(= (first sq) a)
(= (second sq) b))
(f (rest (rest sq)) [a b])
(cons (first sq) (f (rest sq) [a b])))))
not exhaustively tested but seems to work.
A simple solution using lazy-seq, take and drop working for any finite subseq and any (including infinite) sequence that needs to be filtered:
(defn remove-subseq-at-start
[subseq xs]
(loop [xs xs]
(if (= (seq subseq) (take (count subseq) xs))
(recur (drop (count subseq) xs))
xs)))
(defn remove-subseq-all [subseq xs]
(if-let [xs (seq (remove-subseq-at-start subseq xs))]
(lazy-seq (cons (first xs) (remove-subseq subseq (rest xs))))
()))
(deftest remove-subseq-all-test
(is (= ["c" "a"] (remove-subseq-all ["a" "b"] ["a" "b" "a" "b" "c" "a" "a" "b"])))
(is (= ["a"] (remove-subseq-all ["a" "b"] ["a"])))
(is (= ["a" "b"] (remove-subseq-all [] ["a" "b"])))
(is (= [] (remove-subseq-all ["a" "b"] ["a" "b" "a" "b"])))
(is (= [] (remove-subseq-all ["a" "b"] nil)))
(is (= [] (remove-subseq-all [] [])))
(is (= ["a" "b" "a" "b"] (->> (remove-subseq-all ["c" "d"] (cycle ["a" "b" "c" "d"]))
(drop 2000000)
(take 4))))
(is (= (seq "ca") (remove-subseq-all "ab" "ababcaab"))))
If you can ensure that the input is a vector, we can use subvec to check on every element whether the following subvector of the same length matches the pattern. If so, we omit it, otherwise we move ahead to the next element in the vector:
(let [pattern ["a" "b"]
source ["a" "b" "c" "a" "a" "b"]]
(loop [source source
pattern-length (count pattern)
result []]
(if (< (count source) pattern-length)
(into [] (concat result source))
(if (= pattern (subvec source 0 pattern-length))
; skip matched part of source
(recur (subvec source pattern-length) pattern-length result)
; otherwise move ahead one element and save it as result
(recur (subvec source 1) pattern-length
(conj result (first source)))))))
With general sequences, you could use the same approach, substituting take and drop as appropriate.

How does memoize interact with binding in Clojure?

Does memoize keep track of changes to binding which may make returning a computation it has stored incorrect?
For example if I have a function foo such as:
(defn foo [bar baz]
...
(let [config-val *config-val*]
...)
)
which I contain within a binding so I can change the value of *config-val*, does memoizing it mean that if I change the value of *config-val*, but not the parameters to it that it will not recompute the value of the function? Instead it will give me the value of the function with the old configuration?
In Clojure 1.3.0 memoize doesn't keep track of rebinding.
user=> (def ^:dynamic *x* 5)
#'user/*x*
user=> (def f (memoize #(+ *x* %)))
#'user/f
user=> (f 1)
6
user=> (binding [*x* 6] (f 1))
6
user=> (binding [*x* 7] (f 1))
6
Additionally,
user=> (binding [*x* 7] (f 3))
10
user=> (f 3)
10
user=> *x*
5
memoize does not account for binding, this can be confirmed by looking at the source where the map in the atom is keyed only by the arguments. Indeed a function with dynamic rebinding is not "referentially transparent" (i.e. it cannot be replaced with its value).
Is there something that prevents you from passing the *config-val* as an argument, at least to the function you wish to memoize?
user=> (source memoize)
(defn memoize
"Returns a memoized version of a referentially transparent function. The
memoized version of the function keeps a cache of the mapping from arguments
to results and, when calls with the same arguments are repeated often, has
higher performance at the expense of higher memory use."
{:added "1.0"}
[f]
(let [mem (atom {})]
(fn [& args]
(if-let [e (find #mem args)]
(val e)
(let [ret (apply f args)]
(swap! mem assoc args ret)
ret)))))
As the documentation for memoize suggests, a memoized function will keep an internal cache of arguments mapping to results. When a memoized function is called with arguments it has already seen it will do nothing but look up the correct return value from the cache. Nothing will be recomputed and you will get the same result as you got the last time you called the function. Any rebindings will be ignored.
user=> (def ^:dynamic op +)
user=> (defn add [x y] (op x y))
user=> (add 1 2)
3
user=> (binding [op -]
(add 1 2))
-1
user=> (alter-var-root #'add memoize)
user=> (add 1 2)
3
user=> (binding [op -]
(add 1 2))
3

Test whether a list contains a specific value in Clojure

What is the best way to test whether a list contains a given value in Clojure?
In particular, the behaviour of contains? is currently confusing me:
(contains? '(100 101 102) 101) => false
I could obviously write a simple function to traverse the list and test for equality, but there must surely be a standard way to do this?
Ah, contains?... supposedly one of the top five FAQs re: Clojure.
It does not check whether a collection contains a value; it checks whether an item could be retrieved with get or, in other words, whether a collection contains a key. This makes sense for sets (which can be thought of as making no distinction between keys and values), maps (so (contains? {:foo 1} :foo) is true) and vectors (but note that (contains? [:foo :bar] 0) is true, because the keys here are indices and the vector in question does "contain" the index 0!).
To add to the confusion, in cases where it doesn't make sense to call contains?, it simply return false; this is what happens in (contains? :foo 1) and also (contains? '(100 101 102) 101). Update: In Clojure ≥ 1.5 contains? throws when handed an object of a type that doesn't support the intended "key membership" test.
The correct way to do what you're trying to do is as follows:
; most of the time this works
(some #{101} '(100 101 102))
When searching for one of a bunch of items, you can use a larger set; when searching for false / nil, you can use false? / nil? -- because (#{x} x) returns x, thus (#{nil} nil) is nil; when searching for one of multiple items some of which may be false or nil, you can use
(some (zipmap [...the items...] (repeat true)) the-collection)
(Note that the items can be passed to zipmap in any type of collection.)
Here's my standard util for the same purpose:
(defn in?
"true if coll contains elm"
[coll elm]
(some #(= elm %) coll))
You can always call java methods with .methodName syntax.
(.contains [100 101 102] 101) => true
I know that I'm a little bit late, but what about:
(contains? (set '(101 102 103)) 102)
At last in clojure 1.4 outputs true :)
(not= -1 (.indexOf '(101 102 103) 102))
Works, but below is better:
(some #(= 102 %) '(101 102 103))
For what it is worth, this is my simple implementation of a contains function for lists:
(defn list-contains? [coll value]
(let [s (seq coll)]
(if s
(if (= (first s) value) true (recur (rest s) value))
false)))
If you have a vector or list and want to check whether a value is contained in it, you will find that contains? does not work.
Michał has already explained why.
; does not work as you might expect
(contains? [:a :b :c] :b) ; = false
There are four things you can try in this case:
Consider whether you really need a vector or list. If you use a set instead, contains? will work.
(contains? #{:a :b :c} :b) ; = true
Use some, wrapping the target in a set, as follows:
(some #{:b} [:a :b :c]) ; = :b, which is truthy
The set-as-function shortcut will not work if you are searching for a falsy value (false or nil).
; will not work
(some #{false} [true false true]) ; = nil
In these cases, you should use the built-in predicate function for that value, false? or nil?:
(some false? [true false true]) ; = true
If you will need to do this kind of search a lot, write a function for it:
(defn seq-contains? [coll target] (some #(= target %) coll))
(seq-contains? [true false true] false) ; = true
Also, see Michał’s answer for ways to check whether any of multiple targets are contained in a sequence.
Here's a quick function out of my standard utilities that I use for this purpose:
(defn seq-contains?
"Determine whether a sequence contains a given item"
[sequence item]
(if (empty? sequence)
false
(reduce #(or %1 %2) (map #(= %1 item) sequence))))
Here's the classic Lisp solution:
(defn member? [list elt]
"True if list contains at least one instance of elt"
(cond
(empty? list) false
(= (first list) elt) true
true (recur (rest list) elt)))
I've built upon j-g-faustus version of "list-contains?". It now takes any number of arguments.
(defn list-contains?
([collection value]
(let [sequence (seq collection)]
(if sequence (some #(= value %) sequence))))
([collection value & next]
(if (list-contains? collection value) (apply list-contains? collection next))))
It is as simple as using a set - similar to maps, you can just drop it in the function position. It evaluates to the value if in the set (which is truthy) or nil (which is falsey):
(#{100 101 102} 101) ; 101
(#{100 101 102} 99) ; nil
If you're checking against a reasonably sized vector/list you won't have until runtime, you can also use the set function:
; (def nums '(100 101 102))
((set nums) 101) ; 101
The recommended way is to use some with a set - see documentation for clojure.core/some.
You could then use some within a real true/false predicate, e.g.
(defn in? [coll x] (if (some #{x} coll) true false))
(defn in?
[needle coll]
(when (seq coll)
(or (= needle (first coll))
(recur needle (next coll)))))
(defn first-index
[needle coll]
(loop [index 0
needle needle
coll coll]
(when (seq coll)
(if (= needle (first coll))
index
(recur (inc index) needle (next coll))))))
(defn which?
"Checks if any of elements is included in coll and says which one
was found as first. Coll can be map, list, vector and set"
[ coll & rest ]
(let [ncoll (if (map? coll) (keys coll) coll)]
(reduce
#(or %1 (first (filter (fn[a] (= a %2))
ncoll))) nil rest )))
example usage (which? [ 1 2 3 ] 3) or (which? #{ 1 2 3} 4 5 3)
Since Clojure is built on Java, you can just as easily call the .indexOf Java function. This function returns the index of any element in a collection, and if it can't find this element, returns -1.
Making use of this we could simply say:
(not= (.indexOf [1 2 3 4] 3) -1)
=> true
The problem with the 'recommended' solution is it is breaks when the value you are seeking is 'nil'. I prefer this solution:
(defn member?
"I'm still amazed that Clojure does not provide a simple member function.
Returns true if `item` is a member of `series`, else nil."
[item series]
(and (some #(= item %) series) true))
There are convenient functions for this purpose in the Tupelo library. In particular, the functions contains-elem?, contains-key?, and contains-val? are very useful. Full documentation is present in the API docs.
contains-elem? is the most generic and is intended for vectors or any other clojure seq:
(testing "vecs"
(let [coll (range 3)]
(isnt (contains-elem? coll -1))
(is (contains-elem? coll 0))
(is (contains-elem? coll 1))
(is (contains-elem? coll 2))
(isnt (contains-elem? coll 3))
(isnt (contains-elem? coll nil)))
(let [coll [ 1 :two "three" \4]]
(isnt (contains-elem? coll :no-way))
(isnt (contains-elem? coll nil))
(is (contains-elem? coll 1))
(is (contains-elem? coll :two))
(is (contains-elem? coll "three"))
(is (contains-elem? coll \4)))
(let [coll [:yes nil 3]]
(isnt (contains-elem? coll :no-way))
(is (contains-elem? coll :yes))
(is (contains-elem? coll nil))))
Here we see that for an integer range or a mixed vector, contains-elem? works as expected for both existing and non-existant elements in the collection. For maps, we can also search for any key-value pair (expressed as a len-2 vector):
(testing "maps"
(let [coll {1 :two "three" \4}]
(isnt (contains-elem? coll nil ))
(isnt (contains-elem? coll [1 :no-way] ))
(is (contains-elem? coll [1 :two]))
(is (contains-elem? coll ["three" \4])))
(let [coll {1 nil "three" \4}]
(isnt (contains-elem? coll [nil 1] ))
(is (contains-elem? coll [1 nil] )))
(let [coll {nil 2 "three" \4}]
(isnt (contains-elem? coll [1 nil] ))
(is (contains-elem? coll [nil 2] ))))
It is also straightforward to search a set:
(testing "sets"
(let [coll #{1 :two "three" \4}]
(isnt (contains-elem? coll :no-way))
(is (contains-elem? coll 1))
(is (contains-elem? coll :two))
(is (contains-elem? coll "three"))
(is (contains-elem? coll \4)))
(let [coll #{:yes nil}]
(isnt (contains-elem? coll :no-way))
(is (contains-elem? coll :yes))
(is (contains-elem? coll nil)))))
For maps & sets, it is simpler (& more efficient) to use contains-key? to find a map entry or a set element:
(deftest t-contains-key?
(is (contains-key? {:a 1 :b 2} :a))
(is (contains-key? {:a 1 :b 2} :b))
(isnt (contains-key? {:a 1 :b 2} :x))
(isnt (contains-key? {:a 1 :b 2} :c))
(isnt (contains-key? {:a 1 :b 2} 1))
(isnt (contains-key? {:a 1 :b 2} 2))
(is (contains-key? {:a 1 nil 2} nil))
(isnt (contains-key? {:a 1 :b nil} nil))
(isnt (contains-key? {:a 1 :b 2} nil))
(is (contains-key? #{:a 1 :b 2} :a))
(is (contains-key? #{:a 1 :b 2} :b))
(is (contains-key? #{:a 1 :b 2} 1))
(is (contains-key? #{:a 1 :b 2} 2))
(isnt (contains-key? #{:a 1 :b 2} :x))
(isnt (contains-key? #{:a 1 :b 2} :c))
(is (contains-key? #{:a 5 nil "hello"} nil))
(isnt (contains-key? #{:a 5 :doh! "hello"} nil))
(throws? (contains-key? [:a 1 :b 2] :a))
(throws? (contains-key? [:a 1 :b 2] 1)))
And, for maps, you can also search for values with contains-val?:
(deftest t-contains-val?
(is (contains-val? {:a 1 :b 2} 1))
(is (contains-val? {:a 1 :b 2} 2))
(isnt (contains-val? {:a 1 :b 2} 0))
(isnt (contains-val? {:a 1 :b 2} 3))
(isnt (contains-val? {:a 1 :b 2} :a))
(isnt (contains-val? {:a 1 :b 2} :b))
(is (contains-val? {:a 1 :b nil} nil))
(isnt (contains-val? {:a 1 nil 2} nil))
(isnt (contains-val? {:a 1 :b 2} nil))
(throws? (contains-val? [:a 1 :b 2] 1))
(throws? (contains-val? #{:a 1 :b 2} 1)))
As seen in the test, each of these functions works correctly when for searching for nil values.
Another option:
((set '(100 101 102)) 101)
Use java.util.Collection#contains():
(.contains '(100 101 102) 101)
Found this late. But this is what im doing
(some (partial = 102) '(101 102 103))

Resources