如何在Clojure中使用值作为谓词,从键值对列表创建映射?
我刚开始学习Clojure,所以我想我的主要问题是我不知道如何正确地表述问题,以找到现有的解决方案。我有一张地图:如何在Clojure中使用值作为谓词,从键值对列表创建映射?,clojure,Clojure,我刚开始学习Clojure,所以我想我的主要问题是我不知道如何正确地表述问题,以找到现有的解决方案。我有一张地图: {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1} 我想将其“转化”为: i、 e.使用复合键的前两个元素作为新键,第三个元素作为原始映射中具有最高值的键值对的值 我可以轻松创建新的地图结构: => (into {} (for [[[x y z] v] {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1}] [[x y]
{[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1}
我想将其“转化”为:
i、 e.使用复合键的前两个元素作为新键,第三个元素作为原始映射中具有最高值的键值对的值
我可以轻松创建新的地图结构:
=> (into {} (for [[[x y z] v] {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1}] [[x y] {z v}]))
{[0 1] {"b" 1}, [1 1] {"a" 1}}
但是into不接受任何谓词,所以最后一个谓词获胜。我还尝试了:让和合并,但似乎不能正确引用映射,消除不需要的对或在处理时替换映射的值。当您只需要获取一个值序列,而不需要额外的转换时,使用conj从中构造一个结果,Into往往最有用。通过预处理(如排序)或通过简化(允许您执行累加器内省,如此处所需),您正在执行构造的任何其他内容都更适合 首先,我们必须能够比较两个字符串
(defn greater? [^String a ^String b]
(> (.compareTo a b) 0))
现在我们可以编写一个转换,将累加器中的当前值与“下一个”值进行比较,并保持最大值<代码>->为了使更新函数更具可读性而被无偿使用
(defn transform [input]
(-> (fn [acc [[x y z] _]] ;; take the acc, [k, v], destructure k discard v
(let [key [x y]] ;; construct key into accumulator
(if-let [v (acc key)] ;; if the key is set
(if (greater? z v) ;; and z (the new val) is greater
(assoc acc key z) ;; then update
acc) ;; else do nothing
(assoc acc key z)))) ;; else update
(reduce {} input))) ;; do that over all [k, v]s from empty acc
可以通过将一系列序列转换线程连接在一起来实现这一点
(->> data
(group-by #(->> % key (take 2)))
vals
(map (comp first first (partial sort-by (comp - val))))
(map (juxt #(subvec % 0 2) #(% 2)))
(into {}))
;{[0 1] "a", [1 1] "a"}
。。。在哪里
(def data {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1})
您可以逐行构建解决方案。我建议你跟随建筑的脚步,从
(->> data
(group-by #(->> % key (take 2)))
;{(0 1) [[[0 1 "a"] 2] [[0 1 "b"] 1]], (1 1) [[[1 1 "a"] 1]]}
堆叠(惰性)序列层可能运行得相当慢,但Clojure 1.7中提供的转换器将允许您在此习惯用法中编写更快的代码,如中所示 不知道为什么这里需要字符串比较器。OP的数据需要比较原始映射中的值元素,它是一个整数。即[01“a”]=2[01“b”]=1。2>1所以保留第一个键并转换为{[01]“a”}谢谢,这给了我一些想法。但是,您正在丢弃原始值并将z与v进行比较,这不是我的意图。更确切地说,我认为你必须将之前的z集的v保留在某个地方,然后将其与新z测试的v进行比较。这在我看来非常漂亮!直觉上,我想象了一些转换,但当大多数核心功能对我来说仍然不熟悉时,我不可能实现这些转换。我要把它拆开学习,谢谢!
(->> data
(group-by #(->> % key (take 2)))
;{(0 1) [[[0 1 "a"] 2] [[0 1 "b"] 1]], (1 1) [[[1 1 "a"] 1]]}
user> (def m {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1})
#'user/m
user> (->> m
keys
sort
reverse
(mapcat (fn [x]
(vector (-> x butlast vec)
(last x))))
(apply sorted-map))
;=> {[0 1] "a", [1 1] "a"}