2016-04-21 4 views
3

Я только начал изучать Clojure и функциональное программирование и у меня трудное время, пытаясь реализовать следующую задачу:Clojure - Удаление элементов из вектора внутри петли

У меня есть вектор векторов, как это [[аЬ] [ac] [bc] [cd] [db]]. И мне нужно выполнить итерацию, удалив элементы, которые появляются во втором столбце, который уже появился во втором столбце. Например, элементы [b c] и [d b] (поскольку и c, и b уже появились во втором столбце). Мне удалось получить функцию, которая удаляет один элемент в то время, но мне нужно прокручивать вектор для каждого элемента, проверяя и удаляя элементы. Как я могу это достичь? Я думал об использовании рекурсии для достижения этого, но каждая попытка оказалась неудачной. Извините, если это тривиальный вопрос, но я застрял в этом.

Например

Вход: [[аб] [ас] [Ьс] [CD] [объявления] [быть]]

Ouput (ожидаемый): [[аб] [ переменный ток] [CD] [быть]]

Удалены пункты: [[Ьс] [объявления]]

Как вы можете видеть, как с и d уже появились на предыдущих пунктах [AC] и [ cd] соответственно, поэтому Мне нужно удалить элементы [b c] и [a d].

До сих пор, у меня есть следующий код

Эта функция возвращает вектор элементов, подлежащих удалению. В нашем случае он возвращает вектор [[Ьс] [объявления]]

(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

большой вопрос. Я уверен, что pro 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))))))) 

решаемые с петлевой/повторялись. Если у меня есть время, я увижу, могу ли я использовать что-то вроде уменьшения или что-то другое здесь.

Фильтры: [["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]) 

От повернуть на месте преобразователь distinct-by на основе преобразователя Clojures distinct.

(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 выше):

одна только группа, все по второму значению, и принять первый элемент из каждого Валу:

(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]) 

но да, петля/RECUR всегда быстрее я думаю:

(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))))) 
Смежные вопросы