在Clojure中将2元组(x,y)的列表排序到集合的排序映射中

时间:2013-04-16 09:12:22

标签: clojure

我正在尝试使用sorted-map函数创建sorted-set list-of-xy->sorted-map-of-sets

(def in
  '([1 9] [1 8] [1 7]
     [2 1] [2 2] [2 3]
     [2 1] [2 2] [2 3]
     [2 1] [2 2] [2 3]))

(def out
  (into (sorted-map)
    {1 (sorted-set 9 8 7)
     2 (sorted-set 1 2 3)}))

(defn list-of-xy->sorted-map-of-sorted-sets [list-of-xy]
  "Take a list (or lazy-seq) of 2-tuple and return a sorted-map of sorted-sets"
  (reduce ????? list-of-xy))


; should return true
(= (list-of-xy->sorted-map-of-sorted-sets in) out)

到目前为止,我尝试分两步创建out

(def int1
    (group-by #(first %) in))
;=> { 1 [[1 9] [1 8] [1 7]],
;     2 [[2 1] [2 2] [2 3] [2 1] [2 2] [2 3] [2 1] [2 2] [2 3]]}

(def int2
    (flatten
      (map
        #(let [[x xys] %]
           (list x (sorted-set (map last xys))))
        int1)))
;=> (1 #{7 8 9} 2 #{1 2 3}) ; <-- this is not a sorted-map (yet!)

将性能作为优先事项转换in --> out有什么更好的方法?


顺便说一句

@Ankur回答接受了。到目前为止,它是更快的解决方案。

对于我的实际问题,来自@amalloy解决方案(+1)的(update-in acc [x] conj y)通过reduced打开了通往get-in的路。我正在使用的还原功能是:

(fn [a [x y]]
  (if-not (get-in a [x y])
    (update-in a [x] conj y)
    (reduced a)))

2 个答案:

答案 0 :(得分:2)

(= out (into (sorted-map)
             (map (fn [[k v]]
                    [k (apply sorted-set (map second v))])
                  (group-by first in))))

如果这通过了您的性能测试,请告诉我:)。

答案 1 :(得分:1)

(defn list-of-xy->sorted-map-of-sorted-sets [list-of-xy]
  (let [conj (fnil conj (sorted-set))]
    (reduce (fn [acc [x y]]
              (update-in acc [x] conj y))
            (sorted-map)
            list-of-xy)))