Can I make a Deterministic Shuffle in clojure? - random

I'd like to make some shuffles of sets which will be the same every time my program is run:
This is one way to do it:
(def colours ["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"])
(defn colour-shuffle [n]
(let [cs (nth (clojure.math.combinatorics/permutations colours) n)]
[(first cs) (drop 1 cs)]))
; use (rand-int 40320) to make up numbers, then hard code:
(def colour-shuffle-39038 (colour-shuffle 39038))
(def colour-shuffle-28193 (colour-shuffle 28193))
(def colour-shuffle-5667 (colour-shuffle 5667))
(def colour-shuffle-8194 (colour-shuffle 8194))
(def colour-shuffle-13895 (colour-shuffle 13895))
(def colour-shuffle-2345 (colour-shuffle 2345))
colour-shuffle-39038 ; ["white" ("magenta" "blue" "green" "cyan" "yellow" "red" "black")]
But it takes a while to evaluate, and seems wasteful and rather inelegant.
Is there some way of generating shuffle 39038 directly, without generating and consuming all of the sequence?
(I already realise that I can hard code them, or bring the effort back to compile time with a macro. That also seems a bit rubbish.)

clojure.core/shuffle uses java.util.Collection/shuffle, which takes an optional random number generator.
clojure.core/shuffle does not use this argument, but you could use it to create a variation of shuffle that takes an additional seed value argument, and use that seed value to create a random number generator to pass to java.util.Collection/shuffle:
(defn deterministic-shuffle
[^java.util.Collection coll seed]
(let [al (java.util.ArrayList. coll)
rng (java.util.Random. seed)]
(java.util.Collections/shuffle al rng)
(clojure.lang.RT/vector (.toArray al))))

Sounds like you want to number permutations:
(def factorial (reductions * 1 (drop 1 (range))))
(defn factoradic [n] {:pre [(>= n 0)]}
(loop [a (list 0) n n p 2]
(if (zero? n) a (recur (conj a (mod n p)) (quot n p) (inc p)))))
(defn nth-permutation [s n] {:pre [(< n (nth factorial (count s)))]}
(let [d (factoradic n)
choices (concat (repeat (- (count s) (count d)) 0) d)]
((reduce
(fn [m i]
(let [[left [item & right]] (split-at i (m :rem))]
(assoc m :rem (concat left right)
:acc (conj (m :acc) item))))
{:rem s :acc []} choices) :acc)))
Let's try it:
(def colours ["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"])
(nth-permutation colours 39038)
=> ["white" "magenta" "blue" "green" "cyan" "yellow" "red" "black"]
...as in the question, but without generating any of the other permutations.
Well enough, but would we get them all?
(def x (map (partial nth-permutation colours) (range (nth factorial (count colours)))))
(count x)
=> 40320
(count (distinct x))
=> 40320
(nth factorial (count colours))
=> 40320
Note the permutations are generated in (lexicographic by index) order:
user=> (pprint (take 24 x))
(["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"]
["red" "blue" "green" "yellow" "cyan" "magenta" "white" "black"]
["red" "blue" "green" "yellow" "cyan" "black" "magenta" "white"]
["red" "blue" "green" "yellow" "cyan" "black" "white" "magenta"]
["red" "blue" "green" "yellow" "cyan" "white" "magenta" "black"]
["red" "blue" "green" "yellow" "cyan" "white" "black" "magenta"]
["red" "blue" "green" "yellow" "magenta" "cyan" "black" "white"]
["red" "blue" "green" "yellow" "magenta" "cyan" "white" "black"]
["red" "blue" "green" "yellow" "magenta" "black" "cyan" "white"]
["red" "blue" "green" "yellow" "magenta" "black" "white" "cyan"]
["red" "blue" "green" "yellow" "magenta" "white" "cyan" "black"]
["red" "blue" "green" "yellow" "magenta" "white" "black" "cyan"]
["red" "blue" "green" "yellow" "black" "cyan" "magenta" "white"]
["red" "blue" "green" "yellow" "black" "cyan" "white" "magenta"]
["red" "blue" "green" "yellow" "black" "magenta" "cyan" "white"]
["red" "blue" "green" "yellow" "black" "magenta" "white" "cyan"]
["red" "blue" "green" "yellow" "black" "white" "cyan" "magenta"]
["red" "blue" "green" "yellow" "black" "white" "magenta" "cyan"]
["red" "blue" "green" "yellow" "white" "cyan" "magenta" "black"]
["red" "blue" "green" "yellow" "white" "cyan" "black" "magenta"]
["red" "blue" "green" "yellow" "white" "magenta" "cyan" "black"]
["red" "blue" "green" "yellow" "white" "magenta" "black" "cyan"]
["red" "blue" "green" "yellow" "white" "black" "cyan" "magenta"]
["red" "blue" "green" "yellow" "white" "black" "magenta" "cyan"])

My recommendation: use a closure and calculate the permutations only once. Then re-use those permutations to select an element from it. In your function colour-shuffle, the permutations are re-calculated for every call which isn't very efficient.
(use 'clojure.math.combinatorics)
(def colours ["red" "blue" "green" "yellow" "cyan" "magenta" "black" "white"])
(def select-permutation
(let [perms (permutations colours)]
(fn [n]
(nth perms n))))
(defn colour-shuffle [n]
(let [cs (nth (permutations colours) n)]
[(first cs) (drop 1 cs)]))
(time (do (def colour-shuffle-39038 (colour-shuffle 39038))
(def colour-shuffle-28193 (colour-shuffle 28193))
(def colour-shuffle-5667 (colour-shuffle 5667))
(def colour-shuffle-8194 (colour-shuffle 8194))
(def colour-shuffle-13895 (colour-shuffle 13895))
(def colour-shuffle-2345 (colour-shuffle 2345))))
(time (do (def select-permutation-39038 (select-permutation 39038))
(def select-permutation-28193 (select-permutation 28193))
(def select-permutation-5667 (select-permutation 5667))
(def select-permutation-8194 (select-permutation 8194))
(def select-permutation-13895 (select-permutation 13895))
(def select-permutation-2345 (select-permutation 2345))))
(time (do (def colour-shuffle-39038 (colour-shuffle 39038))
(def colour-shuffle-28193 (colour-shuffle 28193))
(def colour-shuffle-5667 (colour-shuffle 5667))
(def colour-shuffle-8194 (colour-shuffle 8194))
(def colour-shuffle-13895 (colour-shuffle 13895))
(def colour-shuffle-2345 (colour-shuffle 2345))))
(time (do (def select-permutation-39038 (select-permutation 39038))
(def select-permutation-28193 (select-permutation 28193))
(def select-permutation-5667 (select-permutation 5667))
(def select-permutation-8194 (select-permutation 8194))
(def select-permutation-13895 (select-permutation 13895))
(def select-permutation-2345 (select-permutation 2345))))
Output:
"Elapsed time: 129.023 msecs"
"Elapsed time: 65.472 msecs"
"Elapsed time: 182.226 msecs"
"Elapsed time: 5.715 msecs"
Note that the second run of time using select-permutation is even faster. This is because results of lazy sequences are cached after calculation. Requesting an element very deep into the lazy-seq will cause all preceding elements to be calculated as well. This is why the first run takes much longer. When requesting the 39039th element from a fresh lazy-seq will cause at least 39040 elements to be calculated (in chucks of 32).
Btw, If your random numbers are going to be hardcoded anyway, you might as well hardcode the above retrieved permutations.

Related

How to convert decimal to hexadecimal in Scheme? (Need to convert RGB to HEX in GIMP)

How to convert decimal to hexadecimal in Scheme?
Need to convert RGB to HEX in GIMP for JSON after:
(set! imgcolor (car (gimp-color-picker image newDraw 1 1 TRUE TRUE 1)))
in Script-fu. Result now is in RGB like: (255 255 255)
Find answer in pallete-export.scm Written by Barak Itkin
; For all the operations below, this is the order of respectable digits:
(define conversion-digits (list "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"
"a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k"
"l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v"
"w" "x" "y" "z"))
; Converts a decimal number to another base. The returned number is a string
(define (convert-decimal-to-base num base)
(if (< num base)
(list-ref conversion-digits num)
(let loop ((val num)
(order (inexact->exact (truncate (/ (log num)
(log base)))))
(result ""))
(let* ((power (expt base order))
(digit (quotient val power)))
(if (zero? order)
(string-append result (list-ref conversion-digits digit))
(loop (- val (* digit power))
(pred order)
(string-append result (list-ref conversion-digits digit))))))))
; Convert a color to a hexadecimal string
; '(255 255 255) => "#ffffff"
(define (color-rgb-to-hexa-decimal color)
(string-append "#"
(pre-pad-number
(convert-decimal-to-base (car color) 16) 2 "0")
(pre-pad-number
(convert-decimal-to-base (cadr color) 16) 2 "0")
(pre-pad-number
(convert-decimal-to-base (caddr color) 16) 2 "0")
)
)
; Присваеваем HEX переменной
(set! imgcolorHEX (color-rgb-to-hexa-decimal imgcolor))

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}

Clojure , increment a counter

I have a collection looking like this:
[({:customer_id "111", :product_id "222"})({:customer_id "333", :product_id "444"}{:customer_id "555", :product_id "666"})...]
And i would like to flag the "position" of the hash in the collection. At the end i would like my hash to look like this:
[({:product_id "222", :number "1"})({:product_id "444", :number "1"}{:product_id "666", :number "2"})...]
I'have try like this:
(->> (pig/load-clj "resources/test0_file")
(pig/map
(fn [ord]
(for [{:keys [product_id]} ord]
(let [nb (swap! (atom 0) inc)]
{:product_id product_id :number nb}))))
But in that case nb is not incrementing. Thanks for you help
map-indexed , assoc and dissoc provide a cleaner solution
(def products ['({:customer_id "111", :product_id "222"})
'({:customer_id "333", :product_id "444"}
{:customer_id "555", :product_id "666"})])
(for [p products]
(map-indexed #(dissoc (assoc %2 :number (str (inc %))) :customer_id ) p))
;user=>(({:number 1, :product_id "222"}) ({:number 1, :product_id "444"} {:number 2, :product_id "666"}))
Resisting the urge to play too much code golf, here's a working implementation:
(def products ['({:customer_id "111", :product_id "222"})
'({:customer_id "333", :product_id "444"}
{:customer_id "555", :product_id "666"})])
(defn number-in-list [products]
(loop [products products counter 1 result []]
(if (empty? products)
(seq result)
(let [[{:keys [product_id]} & ps] products
updated {:product_id product_id :number (str counter)}]
(recur ps (inc counter) (conj result updated))))))
(vec (map number-in-list products))
Here's another:
(vec
(for [product-list products
:let [numbers (iterate inc 1)
pairs (partition 2 (interleave numbers product-list))]]
(for [[number {:keys [product_id]}] pairs]
{:product_id product_id :number (str number)})))
There is some destructuring going on, but it looks like you have that covered.
I assume that the output is what you really want and for some reason care to have a vector of lists and :number as string. If that is not the case you can drop the calls to seq, str and vec.
Note that this implementation is pure and does not use any mutable contructs.
In general, atoms are pretty rare and only used for some kind of (semi) global, mutable state. For such problems as yours it's more idiomatic to use loops, ranges, sequences etc.
To break this down, this returns an infinite sequence of natural numbers:
(iterate inc 1)
; think '(1 (inc 1) (inc (inc 1)) ..)
This bit returns a sequence of numbers and products interleaved (until one of them runs out):
(interleave numbers product-list)
; [first_number first_product second_number second_product ..]
Then we partition it to pairs:
(partition 2 ...)
; [[first_number first_product] [second_number second_product] ...]
... and finally for each of these pairs we construct the record that we wanted.
Given
(def data [[{:customer_id "111", :product_id "222"}]
[{:customer_id "333", :product_id "444"}
{:customer_id "555", :product_id "666"}]])
then
(map
#(map-indexed
(fn [n m]
(assoc
(select-keys m [:product_id])
:number
(str (inc n))))
%)
data)
is
(({:number "1", :product_id "222"})
({:number "1", :product_id "444"}
{:number "2", :product_id "666"}))

Add Differing Ticker Times

Hi can you help me add a way to have different timer lengths for each light. I'm doing a world state/big bang program that creates a traffic light that cycles between green, yellow and red while it goes immediately to green if you hit the Spacebar. I have everything running but I couldn't adjust the ticker to be different its always a constant time.
(require 2htdp/image)
(require 2htdp/universe)
;; =================
;; Constants:
(define WIDTH 600)
(define HEIGHT 350)
(define MTS (empty-scene WIDTH HEIGHT))
(define RAD 50)
(define WIDTH_2 (/ WIDTH 2))
(define CTR-Y (/ HEIGHT 2))
;; =================
;; Functions:
;; trafficLightNext Tests
(check-expect (trafficLightNext "red") "green")
(check-expect (trafficLightNext "yellow") "red")
(check-expect (trafficLightNext "green") "yellow")
;; Traffic Light -> Boolean
;; Find the current-state of a Traffic Light (red, yellow or green)
(define (isRed? current-state)
(string=? "red" current-state))
(define (isYellow? current-state)
(string=? "yellow" current-state))
(define (isGreen? current-state)
(string=? "green" current-state))
;; Traffic Light -> Traffic Light
;; Finds the next state for the Traffic Light
(define (trafficLightNext current-state)
(cond
[(isRed? current-state) "green"]
[(isYellow? current-state) "red"]
[(isGreen? current-state) "yellow"]))
;; Render Tests
(check-expect (bulb "red" "red") (circle RAD "solid" "red"))
(check-expect (bulb "green" "green") (circle RAD "solid" "green"))
(check-expect (bulb "yellow" "red") (circle RAD "outline" "red"))
(define (light=? current-state color)
(string=? current-state color))
;; Traffic Light -> Image
;; Renders the the light
(define (bulb on c)
(if (light=? on c) (circle RAD "solid" c) (circle RAD "outline" c)))
;; Traffic Light -> Image
;; Takes a Traffic Light places the image on the scene
(define (trafficLightRender current-state)
(place-image
(bulb current-state "red")
WIDTH_2
52
(place-image
(bulb current-state "yellow")
WIDTH_2
CTR-Y
(place-image
(bulb current-state "green")
WIDTH_2
298
MTS))))
;; TrafficLight -> TrafficLight
;; Traffic Light changes every second
(define (traffic-light-simulation initial-state)
(big-bang initial-state (on-tick trafficLightNext 1) (to-draw trafficLightRender) (on-key ambulance)))
;; Key -> TrafficLight
;; Changes light to green everytime key is touched
(define (ambulance initial-state key)
(cond [(key=? key " ") "green"]
(else initial-state)))
(check-expect (ambulance "yellow" " ") "green")
(check-expect (ambulance "red" " ") "green")
(check-expect (ambulance "yellow" "d") "yellow")
As this looks like a school assignment, I won't give you a full solution, only leads.
It would have been easier if the rate-expr of the on-tick clause of big-bang were a function taking the current state as input, but this is not the case, so you need a (functional) way around.
One possibility is to make your world state a bit more complicated: instead of being only the current light, it could be the light plus a countdown value. At each tick, you do not immediately change the light, but instead you decrement (subtract 1 from) the counter of the state. When the countdown hits 0, you change the light and reinitialize the countdown to a value that depends on the new light.
The main changes are in the trafficLightNext function and tests, but the rest of the program must also be modified, as the state is different.

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