1

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.

bright-star
  • 6,016
  • 6
  • 42
  • 81
  • 1
    It's not clear what you're trying to do or what you expected `into` to do. `into` just `conj`s the elements of a sequence into the given collection. Since maps are sequences of pairs you end up with a set of the pair in the input map. – Lee Oct 30 '15 at 23:38
  • @Lee I guess it'd be a separate expression, but when does such an apparently finely-tailored object like the one in the `project` example come up then? I would have expected `into #{}` to give me something that all the functions in the Relations section of the clojure cheatsheet could operate sensibly on. – bright-star Oct 30 '15 at 23:40
  • 1
    Maps aren't composed of maps, which is what you expected; maps are composed of mapentries. – Mars Oct 30 '15 at 23:49

1 Answers1

2

into just conjs 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))
Lee
  • 142,018
  • 20
  • 234
  • 287
  • If you want to paste your comment in about what `(into)` does, I'll accept this answer and close it up. I like that idiom. – bright-star Oct 31 '15 at 00:14