2013-04-16 25 views
0
組排序的映射2元組(X,Y)的列表

我試圖與功能list-of-xy->sorted-map-of-sets創建sorted-setsorted-map令到Clojure中

(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爲優先?


BTW

@Ankur答案接受。到目前爲止,這是更快的解決方案。

對於我的實際問題,來自@amalloy解決方案(+1)的(update-in acc [x] conj y)通過get-in打開到reduced的方式。我使用的還原功能是:

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

回答

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

讓我知道這是否通過您的性能測試:)。

+0

Eheh @Ankur,性能測試通過!順便說一句,我也嘗試將'(map second v)'改爲'(map last v)''但是你的版本更快:D –

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))) 
+0

感謝@amalloy,我想知道你的解決方案可以使用「reduced」使用下面的序列來縮減縮減:http://stackoverflow.com/questions/15625341/reduce-a-lazy-sequence-like-a-loop-with-a-condition-in-clojure?謝謝 –

+0

當然,如果你可以知道所有剩餘的列表項目已經在集合中,你可以用'reduced'來提早停下來。儘管如此,很難想象你怎麼知道的。 – amalloy