Замените дубликаты в векторе Clojure

Я пытаюсь заменить дубликаты в векторе с пустыми строками. Однако единственные функции, которые я могу найти, должны удалить дубликаты, не заменить их. Как я могу взять

["ноябрь 2016" "ноября 2016" "ноября 2016" "октября 2016" "октября 2016" "ноябрь 2016"]

и продукция:

["октябрь 2016" "" "ноябрь 2016" "" "" ""]

Все, что я могу найти, возвратится ["октябрь 2016" "ноябрь 2016"] , я в настоящее время достигаю желаемой продукции, делая вложенный doseq , но это кажется неэффективным. Есть ли лучший способ достигнуть этого? Спасибо!

3

5 ответы

Вот стратегия решения.

  1. loop over the items of the vector.
  2. Maintain a set of visited items. It can be used to check for uniqueness.
  3. For each item: if the set contains the current item then insert "" into the result vector.
  4. If the current item is unique then insert it into the result vector and also the set.
  5. Return the result vector when all items are visited.
  6. Optionally: Use a transient result vector for better performance.

Код:

(defn duplicate->empty [xs]
  (loop [xs     (seq xs)
         result []
         found #{}]
        (if-let [[x & xs] (seq xs)]
          (if (contains? found x)
            (recur xs (conj result "") found)
            (recur xs (conj result x) (conj found x)))
          result)))

Запрос его:

(duplicate->empty ["Oct 2016" "Oct 2016" "Nov 2016" "Nov 2016" "Nov 2016" "Nov 2016"])
=> ["Oct 2016" "" "Nov 2016" "" "" ""]
5
добавлено
Законченное устранение проблемы во время начального создания вектора, но это действительно работало также, отмеченное как решение.
добавлено автор Zaden, источник

Версия преобразователя только для полноты.

(defn empty-duplicates
  ([]
   (fn [rf]
     (let [seen (volatile! #{})]
       (fn
         ([] (rf))
         ([res] (rf res))
         ([res x]
          (if (contains? @seen x)
            (rf res "")
            (do (vswap! seen conj x)
                (rf res x))))))))
  ([coll]
   (sequence (empty-duplicates) coll)))

(comment

  (def months ["Oct 2016" "Oct 2016" "Nov 2016" "Nov 2016" "Nov 2016" "Nov 2016"])

  (into [] (empty-duplicates) months) ;=> ["Oct 2016" "" "Nov 2016" "" "" ""]

  )
2
добавлено
(defn eliminate-duplicates [v]
        (let [result (transient (vec (repeat (count v) "")))
              index-of-first-occurences (apply merge-with #(first %&) (map-indexed (fn [x y] {y x}) v))]
            (doall (for [[s pos] index-of-first-occurences]
                       (assoc! result pos s)))
            (persistent! result)))
1
добавлено

в основном то же самое как выше, но использование ленивого поколения последовательности:

(defn rdups
  ([items] (rdups #{} items))
  ([found [x & xs :as items]]
   (when (seq items)
     (if (contains? found x)
       (lazy-seq (cons "" (rdups found xs)))
       (lazy-seq (cons x (rdups (conj found x) xs)))))))

user> (rdups ["Oct 2016" "Oct 2016" "Nov 2016" "Nov 2016" "Nov 2016" "Nov 2016"])
;;=> ("Oct 2016" "" "Nov 2016" "" "" "")
1
добавлено
использует ленивый-seq (как принятый ответ) ПЛЮС снижения петля. смотрит самый чистый путь ко мне.
добавлено автор Phil Cooper, источник

Вы могли использовать , повторяют :

(def months ["Oct 2016" "Oct 2016" "Nov 2016" "Nov 2016" "Nov 2016" "Nov 2016"])

(defn step [[[head & tail] dups res]]
  [tail
   (conj dups head)
   (conj res (if (dups head)
               ""
               head))])

(defn empty-dups [xs]
  (->> (iterate step [xs #{} []])
       (drop-while (fn [[[head] _ _]] head))
       (map #(nth % 2))
       first))

(empty-dups months)
;; => ["Oct 2016" "" "Nov 2016" "" "" ""]
0
добавлено
pro.jvm
pro.jvm
3 503 участник(ов)

Сообщество разработчиков Java Scala Kotlin Groovy Clojure Чат для нач-их: @javastart Наш сайт: projvm.com projvm.ru Наш канал: @proJVM Вакансии: @jvmjobs Конфы: @jvmconf

Clojure — русскоговорящее сообщество
Clojure — русскоговорящее сообщество
433 участник(ов)

Общаемся на темы, посвященный Clojure. Решаем проблемы, обмениваемся опытом и делимся новостями. Вакансии и поиск работы: @clojure_jobs Вам могут быть интересны: @javascript_ru, @nodejs_ru, @ruby_ru, @devops_ru, @devops_jobs