How to filter a persistent map in Clojure?

前端 未结 6 1296
情歌与酒
情歌与酒 2020-12-28 13:10

I have a persistent map which I want to filter. Something like this:

(filter #(-> % val (= 1)) {:a 1 :b 1 :c 2})

The above comes out as

6条回答
  •  我在风中等你
    2020-12-28 13:37

    (into {} (filter #(-> % val (= 1)) {:a 1 :b 1 :c 2}))
    

    Of course this does rebuild the map from a sequence of map entries, but there is no way around it. If you're going to filter the entries by value, you're going to have to go through them one by one to see which values match your predicate and which don't.

    Updated (see comments below):

    With the newly introduced keep function, the source of which you can see here (should work just fine in Clojure 1.1 if you want to backport), this seems like a nice way to go about it if you don't use nil as a key:

    (let [m {:a 1 :b 1 :c 2}]
      (apply dissoc m (keep #(-> % val (= 1) (if nil (key %))) m)))
    ; => {:a 1, :b 1}
    

    Also, if you do actually see a slowdown related to rebuilding your map, you can use a transient map at the rebuilding step:

    (persistent! (loop [m (transient {})
                        to-go (seq [[:a 1] [:b 2]])]
                   (if to-go
                     (recur (apply assoc! m (first to-go))
                            (next to-go))
                     m)))
    ; => {:a 1, :b 2}
    

提交回复
热议问题