2016-04-21 12 views
3

我剛開始學習Clojure的和函數式編程,我有困難的時候試圖執行以下任務:的Clojure - 內環路取下載體項目

我有這樣的向量的向量[AB] [ac] [bc] [cd] [db]]。我需要遍歷它,刪除已經出現在第二列上的第二列上出現的項目。例如項目[b c]和[d b](因爲c和b已經出現在第二列)。我設法得到一個函數,可以刪除一個項目,但是我需要遍歷每個項目的向量來檢查和刪除項目。我怎樣才能做到這一點?我想過使用遞歸來實現這一點,但每次嘗試都以失敗告終。對不起,如果這是一個微不足道的問題,但我堅持這一點。

例如

輸入: [[AB] [AC] [BC]苯並[cd] [AD] [被]]

輸出繼電器(預期): [[AB] [ AC] [CD] [是]

移除的項目: [BC] [廣告]

正如你所看到的,c和d已經出現在之前的項目[交流]和[ cd]分別,所以我必須刪除項目[b c]和[a d]。

到目前爲止,我有以下的代碼

該函數返回被刪除項目的載體。在我們的場景中,它返回向量[BC] [廣告]

(defn find-invalid [collection-data item-to-check] 
    (subvec (vec (filter #(= (second %) item-to-check) collection-data)) 1)) 

(defn find-invalid [collection-data item-to-check] 
    (subvec (vec (filter #(= (second %) item-to-check) collection-data)) 1)) 

這等功能由項目

(defn remove-invalid [collection-data item-position] 
    (vec (concat (subvec collection-data 0 item-position) (subvec collection-data (inc item-position))))) 

的給定索引中刪除從原來的向量一次一個項目這最後一個功能是我做的測試這個邏輯

(defn remove-invalid [original-collection ] 
    (dorun (for [item original-collection] 
     [ 
     (dorun (for [invalid-item (find-invalid original-collection (second item))] 
       [ 
        (cond (> (count invalid-item) 0) 
         (println (remove-invalid original-collection (.indexOf original-collection invalid-item))) 
         ) 
        ])) 
     ]))) 

我覺得遞歸可以解決我的問題,但我希望得到任何幫助,以弄完:)。

在此先感謝。

+0

很好的問題。我相信一個clojure專業人士會來拯救=] – sova

回答

3

一種方法是使用reduce

(first (reduce (fn [[result previous] [a b]] 
       [(if (contains? previous b) 
        result 
        (conj result [a b])) 
        (conj previous b)]) 
       [[] #{}] 
       '[[a b] [a c] [b c] [c d] [d b]])) 
;=> [[a b] [a c] [c d]] 

我們要跟蹤到目前爲止(result),我們已經建立了結果的和集中的項目我們先前發現在第二列(previous)。對於每個新項目,我們檢查previous是否包含第二項b。如果是這樣,我們不會向我們的result添加任何內容。否則,我們conj新條目到result的末尾。我們也conj第二項,b,到previous。由於previous是一組,所以如果previous已經包含b,這將不會執行任何操作。最後,在reduce完成後,我們從結果中取出first項目,這代表我們的最終答案。

+0

這是個竅門。非常感謝 – greenFedoraHat

2

如果我正確理解你的問題,這應該這樣做:

(defn clear [v] 
    (loop [v v existing #{} acc []] 
    (if (empty? v) 
     acc 
     (recur (rest v) 
      (conj existing (second (first v))) 
      (if (some existing [(ffirst v)]) acc (conj acc (first v))))))) 

解決了環/復發。如果我有一些時間,我會看看我是否可以使用諸如reduce之類的東西或任何適合的功能。

此篩選條件:[["a" "b"] ["a" "c"] ["b" "c"] ["c" "d"] ["d" "b"]][["a" "b"] ["a" "c"]]。實現這個

1

下面是類似@Elogent's answer,但使用:as條款,以避免重建的事情:

(defn filtered [stuff] 
    (second 
    (reduce 
    (fn [[seconds ans :as sec-ans] [x y :as xy]] 
     (if (seconds y) 
     sec-ans 
     [(conj seconds y) (conj ans xy)])) 
    [#{} []] 
    stuff))) 

例如,

(filtered '[[a b] [a c] [b c] [c d] [d b]]) 
;[[a b] [a c] [c d]] 
2

如果你可以依靠的重複是連續的作爲例子,與

(->> '[[a b] [a c] [b c] [c d] [a d] [b e]] 
    (partition-by second) 
    (map first)) 
;-> ([a b] [a c] [c d] [b e]) 

Ot herwise實施基於Clojures distinct換能器的distinct-by換能器。

(sequence (distinct-by second) 
      '[[a b] [a c] [b c] [c d] [a d] [b e]]) 

;-> ([a b] [a c] [c d] [b e]) 

實施

(defn distinct-by [f] 
    (fn [rf] 
    (let [seen (volatile! #{})] 
     (fn 
     ([] (rf)) 
     ([result] (rf result)) 
     ([result input] 
      (let [vinput (f input)] ; virtual input as seen through f 
      (if (contains? @seen vinput) 
       result 
       (do (vswap! seen conj vinput) 
        (rf result input))))))))) 
0

只是爲了好玩: 這些的不保留結果的順序,但如果它是確定和你在一起,他們具有相當的表現(重複的可以按任何順序不像上面的partition-by變體):

之一是通過第二值只是組的一切,並採取第一項從每一個VAL:

(map (comp first val) 
    (group-by second '[[a b] [a c] [b c] [c d] [a d] [b e]])) 

;; => ([a b] [a c] [c d] [b e]) 

也有一個很好的辦法做到這一點,使用的有序集合:

(into (sorted-set-by #(compare (second %1) (second %2))) 
     '[[a b] [a c] [b c] [c d] [a d] [b e]]) 
;; => #{[a b] [a c] [c d] [b e]} 

和一多,也沒有保留順序:

(vals (into {} (map (juxt second identity) 
        (rseq '[[a b] [a c] [b c] [c d] [a d] [b e]])))) 
;; => ([b e] [c d] [a c] [a b]) 

但沒錯,環/易復發總是我猜更快:

(defn remove-dupes [v] 
    (loop [[[_ i2 :as pair] & xs :as v] v present #{} res []] 
    (cond (empty? v) res 
      (present i2) (recur xs present res) 
      :else (recur xs (conj present i2) (conj res pair)))))