如何在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]

我刚开始学习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] {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"}