Sathish
Sathish

Reputation: 21090

How to remove multiple keys from a map?

I have a function that removes a key from a map:

(defn remove-key [key map]
  (into {}
        (remove (fn [[k v]] (#{key} k))
                map)))

(remove-key :foo {:foo 1 :bar 2 :baz 3})

How do i apply this function using multiple keys?

(remove-keys [:foo :bar] {:foo 1 :bar 2 :baz 3})

I have an implementation using loop...recur. Is there a more idiomatic way of doing this in Clojure?

(defn remove-keys [keys map]
  (loop [keys keys
         map map]
    (if (empty? keys)
      map
      (recur (rest keys) (remove-key (first keys) map)))))

Upvotes: 37

Views: 19255

Answers (4)

boxed
boxed

Reputation: 4427

I found this type of thing and others to be super annoying in clojure, so to fix it I created the library instar: https://github.com/boxed/instar .

Upvotes: 1

ivant
ivant

Reputation: 3919

As others said use the built-in function instead of writing your own.

However, if this was just an example and you want an answer of how to do that if there wasn't a standard dissoc, then you can use:

(reduce (fn [m k] (remove-key k m)) {:foo 1 :bar 2 :baz 3} [:foo :bar])

Obviously, if you revert the arguments to remove-key it can be written much simpler:

(reduce remove-key {:foo 1 :bar 2 :baz 3} [:foo :bar])

Upvotes: 11

deong
deong

Reputation: 3870

Your remove-key function is covered by the standard library function dissoc. dissoc will remove more than one key at a time, but it wants the keys to be given directly in the argument list rather than in a list. So you can use apply to "flatten" it out.

(apply dissoc {:foo 1, :bar 2, :baz 3} [:foo :bar])
==> {:baz 3}

Upvotes: 64

Jonas
Jonas

Reputation: 19642

dissoc removes one or more keys from a map:

(dissoc {:foo 1 :bar 2 :baz 3} :foo :bar)

or, if you have the keys in a collection

(apply dissoc {:foo 1 :bar 2 :baz 3} [:foo :bar])

Upvotes: 49

Related Questions