How do I use a treemap for a 2 dimensional keys? - data-structures

I want to map a large number of tuples. My map looks something like:
{[1 2] :thing}
Except there may be a few million of them. I have a feeling that a tree-map might be a good thing to test so I'm trying to get it working. I can't seem to get the comparison function right though.
(defn compare
[[x y] [xx yy]]
(cond
(and (= x xx) (= y yy)) 0
(and (<= x xx) (<= y yy)) -1
(and (<= x xx) (> y yy)) -1
(and (> x xx) (<= y yy)) 1
(and (> x xx) (> y yy)) 1))
Some trivial inputs seem to work
user=> (compare [1 1] [1 1])
0
user=> (compare [1 1] [2 2])
-1
user=> (compare [1 2] [2 1])
-1
user=> (compare [2 1] [1 2])
1
But if I create inputs that cover all combinations, the map should consider them all different.
(def inputs
"All tuples of [0-4, 5-10]."
(clojure.math.combinatorics/cartesian-product
(range 0 4)
(range 5 10)))
(def input-pairs
"All possible pairs of tuples"
(clojure.math.combinatorics/cartesian-product inputs inputs))
If I test the comparison function, it returns zero only when the two vectors are structurally identical.
user=> (doseq [[a b] input-pairs]
#_=> (when (zero? (compare a b)) (prn a b)))
(0 5) (0 5)
(0 6) (0 6)
(0 7) (0 7)
(0 8) (0 8)
(0 9) (0 9)
(1 5) (1 5)
etc
So I think my compare function is correct. Using it in the treemap, however, gives some strange results:
(def inputs-kvs
"Inputs in the format that the hash-map and sorted-map constructor understand"
(mapcat #(vector % (apply str %))
(clojure.math.combinatorics/cartesian-product
(range 0 4)
(range 5 10))))
Putting these in a hashmap gives the correct answer
(count (apply assoc (hash-map) inputs-kvs))
=> 20
But putting them in the treemap with the given comparison:
(def structure (sorted-map-by compare))
(count (apply assoc structure inputs-kvs))
=> 4
(apply assoc structure inputs-kvs)
=> {(0 5) "25", (1 6) "36", (2 7) "37", (3 5) "39"}
"25" has been stored in the (0 5) slot. But the compare function doesn't say that (0 5) and (2 5) are the same:
=> (compare [0 5] [2 5])
-1
What am I doing wrong? Can I make this work? Is it even meaningful to project a 2-dimensional space onto a 1-dimensional one?
(To head off a question you may have, yes I've tried a 2-dimensional structure, e.g. (sorted-map 1 (sorted-map 2 :value)), but I'm trying to find alternatives with better performance)

Clojure already comes with it's own compare:
user=> (doc compare)
-------------------------
clojure.core/compare
([x y])
Comparator. Returns a negative number, zero, or a positive number
when x is logically 'less than', 'equal to', or 'greater than'
y. Same as Java x.compareTo(y) except it also works for nil, and
compares numbers and collections in a type-independent manner. x
must implement Comparable
Which behaves the same as OPs own function, but most likely is more efficient:
user=> (compare [1 1] [1 1])
0
user=> (compare [1 1] [2 2])
-1
user=> (compare [2 1] [1 2])
1
The behaviour is documented in the Section about Vectors (IPersistentVector) in the Data Structures docs:
Vectors are compared first by length, then each element is compared in order.
So you can just use sorted-map-by compare from core, or since that's the default anyway just sorted-map for your data structure:
user=> (def m (into {} (let [r #(- (rand-int 10) (rand-int 10))] (for [a (range -1 2) b (range -1 2)] [[(r) (r)] (str a b)]))))
#'user/m
user=> (>pprint m)
{[-7 -4] "10",
[-3 5] "01",
[-5 -7] "00",
[5 2] "11",
[-3 1] "-10",
[7 -4] "-11",
[0 -6] "0-1",
[3 1] "-1-1",
[-8 -1] "1-1"}
nil
user=> (>pprint (into (sorted-map-by compare) m))
{[-8 -1] "1-1",
[-7 -4] "10",
[-5 -7] "00",
[-3 1] "-10",
[-3 5] "01",
[0 -6] "0-1",
[3 1] "-1-1",
[5 2] "11",
[7 -4] "-11"}
nil
user=> (>pprint (into (sorted-map) m))
{[-8 -1] "1-1",
[-7 -4] "10",
[-5 -7] "00",
[-3 1] "-10",
[-3 5] "01",
[0 -6] "0-1",
[3 1] "-1-1",
[5 2] "11",
[7 -4] "-11"}
nil
user=> (assert (= (into (sorted-map-by compare) m) (into (sorted-map) m)))
nil

I just added (vec %) to keep the tuples vectors - should not change anything.
As you can see it works here.
Might it be you have a some older REPL stuff laying around - especially since you alias clojure.core/compare ?
; using your compare function
(def inp (mapcat #(vector (vec %) (apply str %))
(clojure.math.combinatorics/cartesian-product (range 0 4) (range 5 10))))
; => ([0 5] "05" [0 6] "06" [0 7] "07" [0 8] "08" ...
(count inp)
; => 40
(apply assoc structure inp)
; => {[0 9] "09", [0 8] "08", [0 7] "07", [0 6] "06", ....
(count (apply assoc structure inp))
; => 20

Related

LeetCode 1: How to translate the question two sum from ReasonML to Clojure? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I did the question "TwoSum" in ReasonML/Ocaml but I have no idea how to code that in Clojure with similar pseudo algorithm. Please comment how to translate this solution to Clojure
Clojure
(def nums [2 7 11 15])
(def target 9)
(defn two-sum [n xs]
(let [ixs (map vector xs (range (count xs)))]))
ReasonML
module TwoSum: {
let twoSum: (int, Belt.List.t(int)) => list(list(int));
let run: unit => unit;
} = {
let logl = l => l |> Array.of_list |> Js.log;
let concatmap = (xs: list('a), f) => {
List.concat(List.map(x => f(x), xs));
};
let twoSum = (n, xs) => {
let ixs = Belt.List.zip([0, ...range(1, List.length(xs))], xs);
concatmap(ixs, ((i, x)) =>
concatmap(drop(i, ixs), ((j, y)) => x + y == n ? [[i, j]] : [])
);
};
let run = () => {
Printf.printf("1. Two Sum :\n");
let res = twoSum(21, [0, 2, 11, 19, 90, 10]);
res |> logl;
};
};
You can use for to list all the possible index pairs and the :when option to filter pairs that fulfill the two-sum conditions. This will return a sequence of possible solutions. Then you pick the first solution.
(defn two-sum [numbers target]
(let [inds (range (count numbers))]
(first (for [i inds
j inds
:when (and (not= i j)
(= target (+ (nth numbers i)
(nth numbers j)))) ]
[i j]))))
(two-sum [2 7 11 15] 9)
;; => [0 1]
As a slight variation, I would use a helper function indexed to convert [:a :b :c] into:
[[0 :a]
[1 :b]
[2 :c]]
then we get:
(defn indexed
[vals]
(mapv vector (range) vals))
(defn two-sum
[vals tgt]
(let [idx-vals (indexed vals)]
(first
(for [[i x] idx-vals ; destructure each pair => local vars i & x
[j y] idx-vals
:when (and (< i j)
(= tgt (+ x y)))]
[i j]))))
and results
(two-sum [2 7 11 15] 666) => nil
(two-sum [2 7 11 15] 9) => [0 1]
(two-sum [0 1 2 7 11 15] 9) => [2 3]
i would go with more functional style:
starting from creating pairs function:
(defn pairs [data]
(->> data
(iterate rest)
(take-while seq)
(mapcat (fn [[x & xs]] (map (partial vector x) xs)))))
user> (pairs [:a :b :c :d])
;;=> ([:a :b] [:a :c] [:a :d] [:b :c] [:b :d] [:c :d])
then you can generate those pairs of index-to-item tuples:
user> (pairs (map-indexed vector [:a :b :c]))
;;=> ([[0 :a] [1 :b]]
;; [[0 :a] [2 :c]]
;; [[1 :b] [2 :c]])
so that you just need to keep the pairs you need:
(defn sum2 [target data]
(->> data
(map-indexed vector)
pairs
(keep (fn [[[i x] [j y]]]
(when (== target (+ x y))
[i j])))))
user> (sum2 9 [2 7 11 15])
;;=> ([0 1])
another option is to use list comprehensions for that:
(defn sum2 [target data]
(for [[[i x] & xs] (->> data
(map-indexed vector)
(iterate rest)
(take-while seq))
[j y] xs
:when (== target (+ x y))]
[i j]))
user> (sum2 9 [2 7 11 15])
;;=> ([0 1])

reduce a nested vector to another one in Clojure

What is an idiomatic way of handling such stuff in Clojure?
I have:
(def data1
[1 [2 3]])
(def data2
[1 [[2 [3 [4]]]
[22 33]]])
I want to get:
[1 2 3]
and
[[1 2 3 4]
[1 22 33]]
respectively. The nested levels of inner vectors may be of different lengths.
I cannot wrap my head around the nature of such inputs and looking for help. Basically a function should map an input (which is a vector) to an output (vector, also) which, in essence, is a vector of all the "routes" from its head to the innermost elements. This is a vague explanation, will be grateful for a better one.
(defn transform [[f & r]]
(let [rr (apply concat r)]
(if (= (flatten rr) rr)
(vec (cons f rr))
(mapv #(if (vector? %)
(vec (cons f (flatten %)))
[f %])
rr))))
; Test Cases
(transform [1 [2 3]]) => [1 2 3]
(transform [1 [[2 [3 [4]]] [22 33]]]) => [[1 2 3 4] [1 22 33]]
(transform [1 [[2 [3 [4]]] [22 33] 44]]) => [[1 2 3 4] [1 22 33] [1 44]
(transform [1]) => [1]
(transform [1 [2]]) => [1 2]
(defn transform [v]
(let [[x & [xs]] v]
(loop [r xs
res []]
(cond
(empty? r) res
(vector? (first r)) (recur (rest r)
(conj res
(into
(conj [] x)
(flatten (first r)))))
:else (into (conj res x) r)))))
(def data1
[1 [2 3]])
(def data2
[1 [[2 [3 [4]]]
[22 33]]])
(def data3
[1 [[20 25 [30 [40 [50]]]]
[2 3 [4 5 [6 7 [8 9]]]]
[[60] 70 [80 [90 100 [110 120 130 [140 150]]]]]]])
; user=> (transform data1)
; [1 2 3]
; user=> (transform data2)
; [[1 2 3 4] [1 22 33]]
; user=> (transform data3)
; [[1 20 25 30 40 50] [1 2 3 4 5 6 7 8 9] [1 60 70 80 90 100 110 120 130 140 150]]

Debugging thread macro -> or ->> in Clojure

I want to understand how works the following code that is designed for the problem: "Given a sequence of integers, find a continuous subsequence which maximizes the sum of its elements"
defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll)) ; tails (1)
(mapcat #(reductions conj [] %)) ; inits (2)
(apply max-key #(reduce + %)))) ; max sum
so I'd like to see the output of forms (1), (2) and others. I can set breakpoints in Cursive but yet I don't know how to get these values.
I have tried to define a locale variables, for example
(defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll)) ; tails
(let [d #(reductions conj [] %)]
d ) ; inits
(apply max-key #(reduce + %)))
)
(max-subseq-sum [-1, -2, 3, 5, 6, -2, -1, 4, -4, 2, -1])
But i still don't understand how to see d, for example
How to solve this problem?
A simple function that prints and returns its input can be inserted into the chain:
(defn debug [x]
(println x)
x)
(defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll))
(debug)
(mapcat #(reductions conj [] %))
(apply max-key #(reduce + %))))
(max-subseq-sum [-1, -2, 3, 5, 6, -2, -1, 4, -4, 2, -1])
([-1 -2 3 5 6 -2 -1 4 -4 2 -1] (-2 3 5 6 -2 -1 4 -4 2 -1) (3 5 6 -2 -1 4 -4 2 -1) (5 6 -2 -1 4 -4 2 -1) (6 -2 -1 4 -4 2 -1) (-2 -1 4 -4 2 -1) (-1 4 -4 2 -1) (4 -4 2 -1) (-4 2 -1) (2 -1) (-1))
=> [3 5 6 -2 -1 4]
Or, if you want better tracking and don't mind a bit of bulk, you can use a macro that includes the expression in the printout:
(defmacro debugM [expr]
`(let [x# ~expr] ; Save the result of the expression so it isn't evaluated twice
(println '~expr "\n\t" x#)
x#))
(defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll))
(debugM)
(mapcat #(reductions conj [] %))
(apply max-key #(reduce + %))))
(max-subseq-sum [-1, -2, 3, 5, 6, -2, -1, 4, -4, 2, -1])
(take-while seq (iterate rest coll))
([-1 -2 3 5 6 -2 -1 4 -4 2 -1] (-2 3 5 6 -2 -1 4 -4 2 -1) (3 5 6 -2 -1 4 -4 2 -1) (5 6 -2 -1 4 -4 2 -1) (6 -2 -1 4 -4 2 -1) (-2 -1 4 -4 2 -1) (-1 4 -4 2 -1) (4 -4 2 -1) (-4 2 -1) (2 -1) (-1))
=> [3 5 6 -2 -1 4]
There is a nice library called debux
(use '[debux.core])
(defn max-subseq-sum [coll]
(dbg (->> (take-while seq (iterate rest coll)) ; tails (1)
(mapcat #(reductions conj [] %)) ; inits (2)
(apply max-key #(reduce + %)))))
(max-subseq-sum [1 2 3])
dbg: (->> (take-while seq (iterate rest coll)) (mapcat (fn* [p1__1991#] (re ... =>
| (take-while seq (iterate rest coll)) =>
| ([1 2 3] (2 3) (3))
| (mapcat (fn* [p1__1991#] (reductions conj [] p1__1991#))) =>
| ([] [1] [1 2] [1 2 3] [] [2] [2 3] [] [3])
| (apply max-key (fn* [p1__1992#] (reduce + p1__1992#))) =>
| [1 2 3]
I could do by injecting ((fn [x] (println x) x)).
(->> [1 2 3 4 5]
(filter even?)
((fn [x] (println x) x))
first)
that shows
(2 4)
2

Update Submatrix in Larger Matrix in Clojure

How can I update a large matrix, represented as nested vectors, by inserting a smaller submatrix at a particular position.
(def submatrix [[1 1] [1 1]])
(def matrix [[0 0 0] [0 0 0] [0 0 0]])
(def pos [1 1])
(defn update-matrix
"Returns new matrix with the submatrix inserted at the [x y] pos as
the top left position of the submatrix."
[matrix submatrix pos]
; implementation??
)
Desired output: (formatted for readability)
[[0 0 0]
[0 1 1]
[0 1 1]]
My progress so far:
I can update a subvector in a vector:
(def v [0 1 2 3 4 5 6])
(def subv ["x" "y" "z"])
(def pos 2)
(concat (take pos v) subv (drop (+ pos (count subv)) v)
; [0 1 "x" "y" "z" 5 6]
But I don't know where to go from here, or what might be most idiomatic.
Getting it right
We can define the required function as
(defn update-submatrix [m sub-m [x y]]
(replace-subvec
m
(map (fn [l r] (replace-subvec l r y)) (subvec m x) sub-m)
x))
... where (replace-subvec v s start) replaces the elements of vector v from index start with those of sequence s, as long as s lasts. For example,
(replace-subvec (vec (range 10)) (range 3) 5)
; [0 1 2 3 4 0 1 2 8 9]
A clear but slow implementation is
(defn replace-subvec [v s start]
(vec (concat (subvec v 0 start) s (subvec v (+ start (count s))))))
... giving, for the example in the question,
(def submatrix [[1 1] [1 1]])
(def matrix [[0 0 0] [0 0 0] [0 0 0]])
(def pos [1 1])
(update-submatrix matrix submatrix pos)
; [[0 0 0] [0 1 1] [0 1 1]]
Speeding it up
The key to speeding up update-submatrix is to speed up replace-subvec.
We can do so in two ways:
run through the altered elements by incrementing through a loop, and
use a transient collection within the function.
This gives us
(defn replace-subvec [v s start]
(loop [v (transient v), s s, i start]
(if (empty? s)
(persistent! v)
(recur (assoc! v i (first s)) (rest s) (inc i)))))
The effect is identical.
You can reduce over a sequence of update coordinates, at each step copying one item from the submatrix into the appropriate place in the larger matrix:
user> (defn update-matrix [matrix submatrix [y x]]
(reduce (fn [m [row col]]
(assoc-in m [(+ row y) (+ col x)]
(get-in submatrix [row col])))
matrix
(for [y (range (count submatrix))
x (range (count (first submatrix)))]
[y x])))
#'user/update-matrix
user> (update-matrix [[0 0 0] [0 0 0] [0 0 0]] [[1 1] [1 1]] [1 1])
[[0 0 0] [0 1 1] [0 1 1]]
Here's my 15 min. shot at it:
(defn update-matrix
"Returns new matrix with the submatrix inserted at the [x y] pos as
the top left position of the submatrix."
[matrix submatrix pos]
(let [[x y] pos
height (count submatrix)
width (count (get submatrix 0))]
(loop [i 0 m matrix]
(if (< i height)
(let [item (vec (concat (vec (drop-last width (get matrix x))) (get submatrix i)))]
(recur (+ 1 i) (assoc m (+ i y) item)))
m))))
Let me know if that doesn't work.

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