Say I have a key-value pair I've agnostically defined as a key-value map:
(def foo {:bar "baz" :bat "squanch"})
It occurs to me at some later time to do some set operations on it, so I'll need to convert it to a relation, which the Clojure cheatsheet says is a type of set, so I go ahead and grab (into)
and go to it:
(set/project (into #{} foo) [:bar])
#{{}}
Huh?
(into #{} foo)
#{[:bar "baz"] [:bat "squanch"]}
That's not what (project)
expects at all. According to the docs:
;; `project` strips out unwanted key/value pairs from a set of maps.
;; Suppose you have these descriptions of cows:
user=> (def cows #{ {:name "betsy" :id 33} {:name "panda" :id 34} })
#'user/cows
;; You care only about the names. So you can get them like this:
user=> (project cows [:name])
#{{:name "panda"} {:name "betsy"}}
So close.
Should I be expecting (into)
to know what I mean when I convert into one of these types, or is there another way? If it's going to be like this, I might as well just roll my own thing with a few map/flatten calls, but that's exactly what I'm trying to avoid by phrasing things in the more elegant language of sets.
For clarity, here is an example of something I thought would be best done with (set/project)
that seems not to be possible with the above expectations:
(defn exclude-keys "Filters out all but argument-provided keys from a key-value
map."
[input-map excluded-keys]
(-> input-map (select-keys (set/difference (into #{} (keys input-map))
excluded-keys))))
I guess I'm just surprised that it takes that much extra syntax to accomplish in Clojure.
into
just conj
s the elements of a sequence into the given collection e.g.
(into #{} [:a :b :b :c :a])
=> #{:c :b :a}
Since maps are sequences of pairs you end up with a set of the pairs in the input map.
If you just want to remove a collection of keys from a map you can use dissoc
:
(defn exclude-keys "Filters out all but argument-provided keys from a key-value
map."
[input-map excluded-keys]
(apply dissoc input-map excluded-keys))