【问题标题】:Replace Duplicates in Clojure Vector替换 Clojure Vector 中的重复项
【发布时间】:2017-10-21 17:34:20
【问题描述】:

我正在尝试用空字符串替换向量中的重复项。但是,我能找到的唯一功能是删除重复项,而不是替换它们。我该如何服用

["Oct 2016" "Oct 2016" "Nov 2016" "Nov 2016" "Nov 2016" "Nov 2016"]

和输出:

["Oct 2016" "" "Nov 2016" "" "" ""]

我能找到的所有东西都会返回["Oct 2016" "Nov 2016"] 我目前正在通过嵌套doseq 实现所需的输出,但它似乎效率低下。有没有更好的方法来实现这一目标? 谢谢!

【问题讨论】:

    标签: vector clojure


    【解决方案1】:

    这是一个解决方案的策略。

    1. loop 在向量的项目上。
    2. 维护访问项目的set。它可用于检查唯一性。
    3. 对于每个项目:如果集合包含当前项目,则将"" 插入结果向量中。
    4. 如果当前项是唯一的,则将其插入结果向量和集合中。
    5. 访问所有项目时返回结果向量。
    6. 可选:使用transient 结果向量以获得更好的性能。

    代码:

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

    【讨论】:

    • 在初始创建向量时解决了问题,但这确实有效,标记为解决方案。
    【解决方案2】:

    传感器版本只是为了完整性。

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

    【讨论】:

      【解决方案3】:
      (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)))
      

      【讨论】:

        【解决方案4】:

        与上面基本相同,但使用惰性序列生成:

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

        【讨论】:

        • 使用lazy-seq(如接受的ans)加上放弃循环。在我看来是最干净的方式。
        【解决方案5】:

        你可以使用iterate:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-04-22
          • 2019-06-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-14
          • 2021-08-01
          相关资源
          最近更新 更多