Falsy return value using contains? function - clojure

I'm not sure what I am doing wrong here:
(defstruct prefix :a :b :c :d :e)
(def peN (struct prefix "pen" "pe" "pem" "peng" "peny"))
(contains? peN "pen") ;=> false
I expect it to return true. Perhaps I am not using contains? correctly?

Firstly, defstruct is deprecated; you should use defrecord instead:
(defrecord Prefix [a b c d e])
(def pen (->Prefix "pen" "pe" "pem" "peng" "peny"))
(contains? pen "pen") ;=> false
Now, why does this call to contains? return false? Well, records are basically just maps with a bit of extra functionality (that is irrelevant in this case), so this is equivalent to
(def pen {:a "pen" :b "pe" :c "pem" :d "peng" :e "peny"})
(contains? pen "pen") ;=> false
Now, if we look at the docstring of contains?, we can find our answer:
Returns true if key is present in the given collection, otherwise returns false.
In this case, the set of keys in our collection is
(keys pen) ;=> (:a :b :c :d :e)
What we really want is to see whether "pen" is contained in the set of values in pen, like so:
(contains? (set (vals pen)) "pen") ;=> true
But this begs the question: why don't you just make pen a set in the first place?
(def pen #{"pen" "pe" "pem" "peng" "peny"})
(contains? pen "pen") ;=> true

contains? checks for keys, not values. This is one way to find out if your map contains that value:
(some #(= "pen" %)(vals peN))

Related

How do I exit a Clojure walk postwalk on a nested maps on the first true predicate match?

I am using clojure.walk/postwalk to compare a predicate to every map in a nested collection and want to exit with true on the first true. How would I do that? I am ok with it walking the whole data structure and then returning true if there is a true match.
As a corollary question, I guess the same question could apply to when one performs a map as opposed to a postwalk.
UPDATE: this was truly a tired/lazy question; I should have provided a code example. That said, I'm leaving it up in case anyone is currently formulating an answer to my half-baked question. The only thing that is worse than asking one is taking it down after someone has been kind enough to start helping. I will be quite content if no one answers, if they request a better question, or if they just give me suggestions of what to research.
a bit different way to do it, also employing tree-seq:
(defn find-deep [pred data not-found]
(->> data
(tree-seq coll? seq)
(some #(when (pred %) [%]))
((fnil first [not-found]))))
user> (find-deep #(= (:c %) 30) [{:a 10 :b [{:c 20 :d {:c 30}}]}] ::none)
;;=> {:c 30}
user> (find-deep #(= (:c %) 40) [{:a 10 :b [{:c 20 :d {:c 30}}]}] ::none)
;;=> :user/none
You may be interested in this function I call walk-seq. It returns a lazy depth-first sequence over a data structure which you can then seek against to find the first match. I find it to be preferable here because it doesn't require callbacks and exceptions to exit early like clojure.walk/postwalk would.
(defn walk-seq
"Returns a lazy depth-first sequence of all forms within a data structure."
[form]
(tree-seq coll? seq form))
(defn seek
"Find the first element in the collection that matches pred,
else returns not-found. Note that using seek can lead to
poor performance and you should always use indexed data
structures instead of multiple seeks over the same data."
([pred coll]
(seek pred coll nil))
([pred coll not-found]
(reduce (fn [nf x] (if (pred x) (reduced x) nf)) not-found coll)))
Usage of walk-seq:
(walk-seq {:a [{:b -1} {:b 1}] :b 2})
=>
({:a [{:b -1} {:b 1}], :b 2}
[:a [{:b -1} {:b 1}]]
:a
[{:b -1} {:b 1}]
{:b -1}
[:b -1]
:b
-1
{:b 1}
[:b 1]
:b
1
[:b 2]
:b
2)
Combining the two:
(seek (every-pred number? pos?) (walk-seq {:a [{:b -1} {:b 1}] :b 2}))
=>
1
It can be done using postwalk by throwing an exception once the predicate is true as I suggested in the comment. This approach is unconventional but concise and lets us reuse the logic of postwalk for walking the datastructure:
(defn walk-some [pred data]
(try
(clojure.walk/postwalk
#(if (pred %)
(throw (ex-info "Found" {:data %}))
%)
data)
false
(catch clojure.lang.ExceptionInfo e
true)))
(walk-some #(and (number? %) (odd? %)) {:a [[9] 3]})
;; => true
(walk-some #(and (number? %) (even? %)) {:a [[9] 3]})
;; => false
Using exceptions for control flow is rarely needed but occasionally it useful to deviate a bit from convention. You may want to define a custom exception type for improved robustness in case your predicate can throw objects of type ExceptionInfo.

Right way to change a value on a map on clojure

Alright, I'm new to clojure, this should be easy but for the life of me I can't find the answer
Let's say I have this map
(def mymap {:a 10 :b 15})
Now I want to change the value of :a to 5. I don't know how to do this properly
I know update and assoc can make changes but they both receive a function as last argument, which applies to the value. I don't want that, I don't want any function to run, I just want to simply set :a to 5.
I think I can pass an anonymous function that simply returns 5 and ignores the arg, but is this the right way? Doesn't look good to me
(update mymap :a (fn [arg] 5))
assoc does not take a function as its last argument; unless you were wanting to associate a function with a key in the map. (assoc mymap :a 5) does what you want.
I'll add though, update, which does take a function, could be used here as well when combined with constantly or just another function (although there's no reason to use them over assoc):
; constantly returns a function that throws away any arguments given to it,
; and "constantly" returns the given value
(update mymap :a (constantly 5))
; Basically the same as above
(update mymap :a (fn [_] 5))
Do keep in mind that as mymap is immutable, so calling (update mymap :a (constantly 5)) or (assoc mymap :a 5) will return a map {:a 5 :b 15}, further references to mymap will continue to return the original value of {:a 10 :b 15}.
If you want to update the value for later calls, you can look at using atoms.
(defonce mymap (atom {:a 10 :b 15}))
(defn change-mymap [value]
(swap! mymap #(assoc % :a value)))
Just make sure that when you want to reference the value of an atom, you dereference it with the # symbol. For example: (clojure.pprint/pprint #mymap)
When you call (change-mymap 5) this will update the stored mymap value to set :a to a new value, leaving any other key-value pairs in your map alone. This can be helpful when you are mapping in updated state in client/server code when responding to inputs from the other system.
Also note that for nested maps, such as
(defonce nested (atom {:a "a value"
:b {:inner "Another value"
:count 3
:another {:value 5}}}))
You can address a particular value in your map by a path vector. You can use the get-in function to retrieve the value (get-in #nested [:b :another :value])
and you can use assoc-in or update-in with a path to update the values. This also allows you to extend a map. For example, with the above value of nested, you can add a whole section to the tree:
(swap! nested #(assoc-in % [:a :b :c :d] "foo"))
will update the initial map to look like this:
{:a {:b {:c {:d "foo"}}}
:b {:inner "Another value"
:count 3
:another {:value 5}}}

clojure map, what is %2 and %1

I am doing a clojure excersice and this is one question.
(true? (__ :a {:a nil :b 2}))
the answer is :
#(nil?(%2 %1 0))
But I could not get it.
What does %2 %1 0 do here?
Especially, what does that 0 do there?
can you explain it for me?
thanks
The #() format is shorthand for defining anonymous functions.
For example: #(+ %1 %2) is the equivalent of (fn [a,b] (+ a b))
Here %2 and %1 represent the second and the first argument to the function respectively.
As it was mentioned earlier,
#(nil? (%2 %1 0)) is a sugar for
(fn [a-map a-key] (nil? (a-map a-key 0)))
A few things to notice about this line:
hash maps in clojure support the function semantics, so using the map in place of function is identical to calling get function
(a-map a-key default-value) equals to (get a-map a-key default-value)
zero as a default key is added to distinguish the abscence of key from a nil value of key. For example:
(get {:b 1} :a) produces nil (as there is no :a key in the map)
(get {:a nil :b 1} :a) also produces nil (as nil is a value of :a)
while using the default value removes this uncertainty:
(get {:b 1} :a 0) => 0
(get {:a nil :b 1} :a 0) => nil
the map in the example has numeric values, so using zero as a default value can lead to even bigger mess (well, depending on the use case. Sometimes zero is exactly what you need here). It is common to use some value that can't be there, for example a keyword like :not-found
But in this case you would probably want to do the task this way:
(true? (#(contains? %2 %1) :a {:a nil :b 2}))
As they obviously want you to check if the key :a is present in a map

Update multiple elements of a Clojure atom within a single swap statement?

I have an atom that has two parts to it.
(def thing (atom {:queue '() :map {}}))
I want to update both :queue and :map in one atomic stroke, to prevent them from getting off-sync.
Queue individually:
(swap! thing update-in [:queue] (list 1))
(From this question: How to append to a nested list in a Clojure atom?)
Map individually:
(swap! thing assoc-in [:map 1] (:key :value))
(From this question: Using swap to MERGE (append to) a nested map in a Clojure atom?)
How can I do these both within a single swap statement? (assuming that would prevent them from getting off-sync?)
You have one change you want to make, right? And you could write that change as a pure function? All you need to do is write that function, and pass it as the argument to swap!.
(defn take-from-queue [{q :queue, m :map}]
{:queue (rest q), :map (assoc m :new-task (first q))})
(swap! thing take-from-queue)
Where of course I have no idea what you actually want the body of your function to do, so I've made up something that doesn't throw an exception.
Say you have a hash-map atom:
(def m1 (atom {:a "A" :b "B"}))
To change :a and :b at the same time, changing their values to values that are different, say the numbers 1 and 2, use this function:
(defn my-swap! [params]
(swap! m1 (fn [old new] new) params))
, like so:
(my-swap! {:a 1 :b 2}) ;=> {:a 1, :b 2}
And the same effect could be achieved with the following function and execution:
(defn my-multi-swap! [params1 params2]
(swap! m1 (fn [old new1 new2] new2) params1 params2))
(my-multi-swap! {} {:a 1 :b 2}) ;=> {:a 1, :b 2}
Normally reset! is used if you want to ignore the old value. Here we use it:
(defn my-merge-swap! [params]
(swap! m1 (fn [old new] (merge old new)) params))
(my-merge-swap! {:b 3}) ;=> {:a "A", :b 3}
The first parameter to the swap! function is the existing value of the atom, and you must pass in one or more extra parameters, which you can use to give the atom its new value.

clojure filter map by keys

I'm following this example: http://groups.google.com/group/clojure/browse_thread/thread/99b3d792b1d34b56
(see the last reply)
And this is the cryptic error that I get:
Clojure 1.2.1
user=> (def m {:a "x" :b "y" :c "z" :d "w"})
#'user/m
user=> (filter #(some % [:a :b]) m)
java.lang.IllegalArgumentException: Key must be integer
(user=>
Also I don't understand why this would even work. Isn't (some ...) going to return the first matching value, "x", every time? I'm a total noob at clojure and just trying to learn.
Please enlighten me.
I guess I just needed to read the docs more:
(select-keys m [:a :b])
Although I'm still not sure what the intention was with the example I found...
If you "iterate" over a map, you'll get key-value pairs rather than keys. For instance,
user=> (map #(str %) {:a 1, :b 2, :c 3})
("[:a 1]" "[:b 2]" "[:c 3]")
Thus your anonymous function tries to evaluate (some [:a "x"] [:a :b]) which clearly does not work.
The ideomatic solution is to use select-keys as mentioned in another answer.
(filter
(fn [x]
(some #{(key x)} [:a :b])) m)
Would do the same using filter and some (but uglier and slower).
This works by filter all from m if some [:a :b] is in the set #{(key x)} (i.e. using a set as predicate) then return the map entry.