Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Clojure中过滤持久映射?_Clojure - Fatal编程技术网

如何在Clojure中过滤持久映射?

如何在Clojure中过滤持久映射?,clojure,Clojure,我有一个要筛选的持久映射。大概是这样的: (filter #(-> % val (= 1)) {:a 1 :b 1 :c 2}) 上面显示为([:a1][:b1])(一个懒散的映射条目序列)。但是我想成为get{:a1:b1} 如何过滤贴图,使其保持为贴图,而不必从一系列贴图条目重新构建它 (into {} (filter #(-> % val (= 1)) {:a 1 :b 1 :c 2})) 当然,这确实可以从一系列映射条目重建映射,但是没有办法绕过它。如果要按值筛选条目,则

我有一个要筛选的持久映射。大概是这样的:

(filter #(-> % val (= 1)) {:a 1 :b 1 :c 2})
上面显示为
([:a1][:b1])
(一个懒散的映射条目序列)。但是我想成为get
{:a1:b1}

如何过滤贴图,使其保持为贴图,而不必从一系列贴图条目重新构建它

(into {} (filter #(-> % val (= 1)) {:a 1 :b 1 :c 2}))
当然,这确实可以从一系列映射条目重建映射,但是没有办法绕过它。如果要按值筛选条目,则必须逐个检查条目,以查看哪些值与谓词匹配,哪些不匹配

更新(见以下评论):

通过新引入的
keep
函数,您可以看到该函数的源代码(如果您想备份,在Clojure 1.1中应该可以正常工作),如果您不使用
nil
作为键,这似乎是一种很好的方法:

此外,如果确实看到与重建贴图相关的减速,则可以在重建步骤中使用瞬态贴图:

(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}

根据您对MichałMarczyk的评论:

(defn filter* [f map]
  (reduce (fn [m [k v :as x]]
            (if-not (f x)
              (dissoc m k)
              m))
          map map))

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

与Michał的版本相比,我认为您不会从中获得太多好处。

需要遍历所有条目,但可以利用Clojures持久映射:

(apply dissoc my-map (for [[k v] my-map :when (not= v 1)] k))
还有一个:

(let [m {:a 1 :b 2 :c 1}]
  (select-keys m (for [[k v] m :when (= v 1)] k)))

基于kotarak的版本,我尝试了自己的宏。这是我第一次做一些有用的事情,所以请容忍我,欢迎评论

(defmacro filter-map [bindings pred m]
  `(select-keys ~m
    (for [~bindings ~m
      :when ~pred]
      ~(first bindings)
    )
  )
)
范例

user=> (filter-map [key val] (even? (:attr val)) {:a {:attr 2} :b {:attr 3} :c {:attr 4}})
{:c {:attr 4}, :a {:attr 2}}

下面是另一个使用
reducekv

(defn filter-kv [pred map]
  (reduce-kv (fn [accumulator key value]
               (if (pred key value)
                 (assoc accumulator key value)
                 accumulator)) {} map))
用法


理论上,你可以通过返回一个带有dissoc-ed键的映射(对应于不匹配的值),让它按值过滤,而无需重建。我希望有一种语言支持的方式来做这件事。好的,我明白你的意思。我会在一秒钟内增加两种方法,但请注意,你不太可能在绩效部门看到巨大的收益(除非你有一张非常大的地图,你只需要敲打一小部分钥匙)。嗯,事实上,与其说是“两种方法”,不如说是“一种方法做,一种方法不用担心重建”。并不是说你很可能需要担心。:-)转化为瞬态连接器!,所以我不确定循环重现是否有意义
(defn filter-kv [pred map]
  (reduce-kv (fn [accumulator key value]
               (if (pred key value)
                 (assoc accumulator key value)
                 accumulator)) {} map))
(filter-kv (fn [key _]
             (not (= key "a"))) {"a" {:some "a"}
                                 "b" {:some "b"}
                                 "c" {:some "c"}})

>> {"b" {:some "b"}
    "c" {:some "c"}}