normally when you print a map, the values are unquoted.
(print {:abc "0" :def "1"}) results in {:abc 0 :def 1}. I would like the output to look like {:abc "0" :def "1"}
I attempted to use the map function to get at every key-value pair and that did not work.
This was my attempt:
(defn print-map [m]
(print "{")
(map #((print (first %) "\"" (second %) "\",")) m)
(print "}\n")
)
nothing from the map gets printed
just use pr/prn instead of print/println, since they generate the string that could be read back by reader, meaning the strings would be quoted:
user=> (prn {:a "10" :b 20 :c "21"})
{:a "10", :b 20, :c "21"}
nil
(print (str {:a "82834"}))
;{:a "82834"}
=> nil
Related
May be, it is a stupid question, but it may help many of newbies. How do I add a key-value pair to the map?
I mean something like:
(defn init-item [v item]
(let [{:keys [id value]} item]
(-> v
(assoc :{ID_AS_A_KEY} value))))
And I get:
(init-item {} {:id "123456789" :value [:name "King" :surname "Leonid"]})
user=> {:123456789 [:name "King" :surname "Leonid"]}
Just don't do it. Use the string itself as your map key. There's no reason to make it a keyword. It's much easier to work with if you leave it alone.
(defn init-item [v item]
(assoc v (:id item) (:value item)))
I think this is what you meant to do:
(defn init-item
[dest-map item]
(let [item-id-str (:id item)
item-val (:value item)
item-id-kw (keyword item-id-str)]
(assoc dest-map item-id-kw item-val)))
(let [all-items {:a 1 :b 2 :c 3}
item-1 {:id "123456789"
:value [:name "King" :surname "Leonid"]}]
(init-item all-items item-1)
;=> {:a 1, :b 2, :c 3, :123456789 [:name "King" :surname "Leonid"]}
Clojure has functions name, symbol, and keyword to convert between strings and symbols/keywords. Since you already have the ID as a string, you just need to call keyword to convert it.
Be sure to always keep a browser tab open to The Clojure CheatSheet.
I am new to Clojure. I am trying to use java hashmap in clojure. I am passing a java hashmap to Clojure. The map is- {0=Goa, 1=Delhi, 2=Mumbai}. When I am trying to use the clojure functions on this map I am not getting the expected output. In contrast to this when I am iterating over this map it is giving the expected output.
Example
(println(get map 0)) is giving nil
(doseq [[key value] map
(println value)) is giving the expected output.
Output-Goa
Delhi
Mumbai
Can somebody please expain me why is this happening?
You really should google a bit to find pre-existing answers like this one: Clojure: working with a java.util.HashMap in an idiomatic Clojure fashion
You can then see a simple answer:
(def data {:a 1 :b 2 :c 3})
(def java-map (java.util.HashMap. data))
(def clj-map (into {} java-map))
which gives us:
java-map => <#java.util.HashMap {:b 2, :c 3, :a 1}>
clj-map => <#clojure.lang.PersistentArrayMap {:b 2, :c 3, :a 1}>
and looping:
(doseq [[k v] clj-map]
(println (format "key=%s val=%s" k v)) )
with result:
key=:b val=2
key=:c val=3
key=:a val=1
I think your problem is that your map is named "map" which is also a Clojure function. Try it like this:
(def my-map {0 "Goa" 1 "Delhi" 2 "Mumbai"})
Which then will work like this:
(println (get my-map 0))
Note that it still returns nil, since there is nothing else after the (println) form but it does print the value of the 0 in the map, which is "Goa".
(def input-map {0 "Goa" 1 "Delhi" 2 "Mumbai"})
(map (fn[[k v]] (print "key " k " value " k)) input-map)
[[k v]] for function let you access key and value for each entry
(map print input-map)
here map entry will be passed as parameter to print
I've obfuscated this code.
Why does this work:
(let [
items [{:var1 x, :var2 x, :var3 (:something x), :var4 (:something2 x)}]
;..........
(my-func items) ; ok
whereas this produces an exception:
(let [
items (map (fn [x] ({:var1 x, :var2 x, :var3 (:something x), :var4 (:something2 x)})) (db/get-items-from-db))
;..........
(my-func items) ; error
which is
Wrong number of args (0) passed to: PersistentArrayMap
When we strip it down to the bones, we have this:
(map (fn [x] ({:a x :b (:c x)})) '({:c "abc"}))
Which produces your error.
The problem is that there are parentheses around the map definition, thus, the map is being treated as a function, and there are no arguments given to it in this case. Remove the parens, and it works:
(map (fn [x] {:a x :b (:c x)}) '({:c "abc"}))
;; ({:a {:c "abc"}, :b "abc"})
It would be the same error as trying to do this:
(defn func [x]
({:a x :b (:c x)}))
When in fact you want:
(defn func [x]
{:a x :b (:c x)})
It may help to further understand if we remember that a map may be used as a function, with the argument specifying which key's value to return:
({:a 1 :b 2} :b)
;; 2
though we often do the reverse and use the key as the function:
(:b {:a 1 :b 2})
;; 2
So we could also remove the error by specifying an argument (in this case :b) to the map being created, though it would not produce the implied desired result:
(map (fn [x] ({:a x :b (:c x)} :b)) '({:c "abc"}))
;; ("abc")
This code extracts all values from vector of maps.
(def vector-of-maps [{:a "1" :b "2"}{:a "3" :b "4"}])
(mapcat vals vector-of-maps)
so I get
("1" "2" "3" "4")
I want to get values only from :a to get
("1" "3")
What way can I do it ?
(def vector-of-maps [{:a "1" :b "2"} {:a "3" :b "4"}])
(map :a vector-of-maps)
yields
("1" "3")
map will apply :a as a function which will extract value from each value in vector-of-maps.
You can do it like this:
(map val (filter (comp #{:a} key) (apply concat vector-of-maps)))
Explanation:
apply concat converts a sequence of maps to a sequence of all the key-value pairs from all those maps
filter (comp #{:a} key) keeps only the key-value pairs whose keys are in the one-element set #{:a}
map val gets the value from each remaining key-value pair
Example:
(def vector-of-maps [{:a "1" :b "2"} {:a "3" :b "4"}])
(map val (filter (comp #{:a} key) (apply concat vector-of-maps)))
;=> ("1" "3")
What is the idiomatic way of counting certain properties of a nested map of maps in Clojure?
Given the following datastructure:
(def x {
:0 {:attrs {:attributes {:dontcare "something"
:1 {:attrs {:abc "some value"}}}}}
:1 {:attrs {:attributes {:dontcare "something"
:1 {:attrs {:abc "some value"}}}}}
:9 {:attrs {:attributes {:dontcare "something"
:5 {:attrs {:xyz "some value"}}}}}})
How can i produce the desired output:
(= (count-attributes x) {:abc 2, :xyz 1})
This is my best effort so far:
(defn count-attributes
[input]
(let [result (for [[_ {{attributes :attributes} :attrs}] x
:let [v (into {} (remove (comp not :attrs) (vals attributes)))]]
(:attrs v))]
(frequencies result)))
Which produces the following:
{{:abc "some value"} 2, {:xyz "some value"} 1}
I like building such functions with threadding so the steps are easier to read
user> (->> x
vals ; first throw out the keys
(map #(get-in % [:attrs :attributes])) ; get the nested maps
(map vals) ; again throw out the keys
(map #(filter map? %)) ; throw out the "something" ones.
flatten ; we no longer need the sequence sequences
(map vals) ; and again we don't care about the keys
flatten ; the map put them back into a list of lists
frequencies) ; and then count them.
{{:abc "some value"} 2, {:xyz "some value"} 1}
(remove (comp not :attrs) is a lot like select-keys
for [[_ {{attributes :attributes} :attrs}] reminds me of get-in
I find tree-seq very useful for these cases:
(frequencies (filter #(and (map? %) (not-any? map? (vals %))) (tree-seq map? vals x)))