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

Order a list of 2-tuple (x,y) into a sorted-map of sets in Clojure

我正在尝试使用功能list-of-xy->sorted-map-of-sets创建sorted-setsorted-map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(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

1
2
3
4
5
6
7
8
9
10
11
12
(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

BTW

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

对于我的实际问题,@ amalloy解决方案(+1)中的(update-in acc [x] conj y)为通过get-in通往reduced的方式打开了道路。 我正在使用的归约函数是:

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


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

让我知道这是否通过了您的性能测试:)。


1
2
3
4
5
6
(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)))